Skip to content

Fold ConstraintSolver::coerceToRValue into TypeChecker::coerceToRValue() #10276

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 3 commits into from
Jun 15, 2017
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
2 changes: 0 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -733,8 +733,6 @@ NOTE(previous_precedence_group_decl,none,

ERROR(tuple_conversion_not_expressible,none,
"cannot express tuple conversion %0 to %1", (Type, Type))
ERROR(load_of_explicit_lvalue,none,
"%0 variable is not being passed by reference", (Type))

//------------------------------------------------------------------------------
// Expression Type Checking Errors
Expand Down
35 changes: 9 additions & 26 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7285,32 +7285,15 @@ namespace {
} // end anonymous namespace

Expr *ConstraintSystem::coerceToRValue(Expr *expr) {
// Can't load from an inout value.
if (auto *iot = getType(expr)->getAs<InOutType>()) {
// Emit a fixit if we can find the & expression that turned this into an
// inout.
auto &tc = getTypeChecker();
if (auto addrOf =
dyn_cast<InOutExpr>(expr->getSemanticsProvidingExpr())) {
tc.diagnose(expr->getLoc(), diag::load_of_explicit_lvalue,
iot->getObjectType())
.fixItRemove(SourceRange(addrOf->getLoc()));
return coerceToRValue(addrOf->getSubExpr());
} else {
tc.diagnose(expr->getLoc(), diag::load_of_explicit_lvalue,
iot->getObjectType());
return expr;
}
}

// If we already have an rvalue, we're done, otherwise emit a load.
if (auto lvalueTy = getType(expr)->getAs<LValueType>()) {
propagateLValueAccessKind(expr, AccessKind::Read);
return cacheType(new (getASTContext())
LoadExpr(expr, lvalueTy->getObjectType()));
}

return expr;
auto &tc = getTypeChecker();
return tc.coerceToRValue(expr,
[&](Expr *expr) {
return getType(expr);
},
[&](Expr *expr, Type type) {
expr->setType(type);
cacheType(expr);
});
}

/// Emit the fixes computed as part of the solution, returning true if we were
Expand Down
38 changes: 21 additions & 17 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2856,39 +2856,43 @@ bool TypeChecker::isSubstitutableFor(Type type, ArchetypeType *archetype,
return true;
}

Expr *TypeChecker::coerceToRValue(Expr *expr) {
Expr *TypeChecker::coerceToRValue(Expr *expr,
llvm::function_ref<Type(Expr *)> getType,
llvm::function_ref<void(Expr *, Type)> setType) {
Type exprTy = getType(expr);

// If expr has no type, just assume it's the right expr.
if (!expr->getType())
if (!exprTy)
return expr;

Type exprTy = expr->getType();


// If the type is already materializable, then we're already done.
if (!exprTy->hasLValueType())
return expr;

// Load lvalues.
if (auto lvalue = exprTy->getAs<LValueType>()) {
expr->propagateLValueAccessKind(AccessKind::Read);
return new (Context) LoadExpr(expr, lvalue->getObjectType());
auto result = new (Context) LoadExpr(expr, lvalue->getObjectType());
setType(result, lvalue->getObjectType());
return result;
}

// Walk into parenthesized expressions to update the subexpression.
if (auto paren = dyn_cast<IdentityExpr>(expr)) {
auto sub = coerceToRValue(paren->getSubExpr());
auto sub = coerceToRValue(paren->getSubExpr(), getType, setType);
paren->setSubExpr(sub);
paren->setType(sub->getType());
setType(paren, getType(sub));
return paren;
}

// Walk into 'try' and 'try!' expressions to update the subexpression.
if (auto tryExpr = dyn_cast<AnyTryExpr>(expr)) {
auto sub = coerceToRValue(tryExpr->getSubExpr());
auto sub = coerceToRValue(tryExpr->getSubExpr(), getType, setType);
tryExpr->setSubExpr(sub);
if (isa<OptionalTryExpr>(tryExpr) && !sub->getType()->hasError())
tryExpr->setType(OptionalType::get(sub->getType()));
if (isa<OptionalTryExpr>(tryExpr) && !getType(sub)->hasError())
setType(tryExpr, OptionalType::get(getType(sub)));
else
tryExpr->setType(sub->getType());
setType(tryExpr, getType(sub));
return tryExpr;
}

Expand All @@ -2897,11 +2901,11 @@ Expr *TypeChecker::coerceToRValue(Expr *expr) {
bool anyChanged = false;
for (auto &elt : tuple->getElements()) {
// Materialize the element.
auto oldType = elt->getType();
elt = coerceToRValue(elt);
auto oldType = getType(elt);
elt = coerceToRValue(elt, getType, setType);

// If the type changed at all, make a note of it.
if (elt->getType().getPointer() != oldType.getPointer()) {
if (getType(elt).getPointer() != oldType.getPointer()) {
anyChanged = true;
}
}
Expand All @@ -2911,11 +2915,11 @@ Expr *TypeChecker::coerceToRValue(Expr *expr) {
SmallVector<TupleTypeElt, 4> elements;
elements.reserve(tuple->getElements().size());
for (unsigned i = 0, n = tuple->getNumElements(); i != n; ++i) {
Type type = tuple->getElement(i)->getType();
Type type = getType(tuple->getElement(i));
Identifier name = tuple->getElementName(i);
elements.push_back(TupleTypeElt(type, name));
}
tuple->setType(TupleType::get(elements, Context));
setType(tuple, TupleType::get(elements, Context));
}

return tuple;
Expand Down
8 changes: 7 additions & 1 deletion lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -1747,7 +1747,13 @@ class TypeChecker final : public LazyResolver {

/// \brief Coerce the given expression to materializable type, if it
/// isn't already.
Expr *coerceToRValue(Expr *expr);
Expr *coerceToRValue(Expr *expr,
llvm::function_ref<Type(Expr *)> getType
= [](Expr *expr) { return expr->getType(); },
llvm::function_ref<void(Expr *, Type)> setType
= [](Expr *expr, Type type) {
expr->setType(type);
});

/// Require that the library intrinsics for working with Optional<T>
/// exist.
Expand Down
19 changes: 19 additions & 0 deletions validation-test/compiler_crashers_2_fixed/0106-rdar32700180.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %target-swift-frontend %s -emit-ir
// REQUIRES: objc_interop

func f(_: AnyObject?) { }

class C {
private var a: Int
private var b: Int

func test() {
f((self.a, self.b) as AnyObject)
}

init() {
a = 0
b = 0
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// REQUIRES: asserts
// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
&_ is Character