Skip to content

[ConstraintSystem] Do not attempt to force references of unapplied fu… #14754

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
Feb 21, 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
108 changes: 54 additions & 54 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,10 +544,11 @@ namespace {

public:
/// \brief Build a reference to the given declaration.
Expr *buildDeclRef(ValueDecl *decl, DeclNameLoc loc, Type openedType,
Expr *buildDeclRef(OverloadChoice choice, DeclNameLoc loc, Type openedType,
ConstraintLocatorBuilder locator, bool implicit,
FunctionRefKind functionRefKind,
AccessSemantics semantics) {
auto *decl = choice.getDecl();
// Determine the declaration selected for this overloaded reference.
auto &ctx = cs.getASTContext();

Expand Down Expand Up @@ -612,7 +613,7 @@ namespace {
if (auto fnConv = dyn_cast<FunctionConversionExpr>(refExpr))
refExpr = fnConv->getSubExpr();

return forceUnwrapIfExpected(refExpr, decl, locator);
return forceUnwrapIfExpected(refExpr, choice, locator);
}
}
}
Expand All @@ -623,7 +624,7 @@ namespace {
TypeExpr::createImplicitHack(loc.getBaseNameLoc(), baseTy, ctx);
cs.cacheExprTypes(base);

return buildMemberRef(base, openedType, SourceLoc(), decl, loc,
return buildMemberRef(base, openedType, SourceLoc(), choice, loc,
openedFnType->getResult(), locator, locator,
implicit, functionRefKind, semantics,
/*isDynamic=*/false);
Expand Down Expand Up @@ -659,7 +660,7 @@ namespace {
loc, implicit, semantics, type);
cs.cacheType(declRefExpr);
declRefExpr->setFunctionRefKind(functionRefKind);
return forceUnwrapIfExpected(declRefExpr, decl, locator);
return forceUnwrapIfExpected(declRefExpr, choice, locator);
}

/// Describes an opened existential that has not yet been closed.
Expand Down Expand Up @@ -899,11 +900,12 @@ namespace {

/// \brief Build a new member reference with the given base and member.
Expr *buildMemberRef(Expr *base, Type openedFullType, SourceLoc dotLoc,
ValueDecl *member, DeclNameLoc memberLoc,
OverloadChoice choice, DeclNameLoc memberLoc,
Type openedType, ConstraintLocatorBuilder locator,
ConstraintLocatorBuilder memberLocator, bool Implicit,
FunctionRefKind functionRefKind,
AccessSemantics semantics, bool isDynamic) {
ValueDecl *member = choice.getDecl();
auto &tc = cs.getTypeChecker();
auto &context = tc.Context;

Expand Down Expand Up @@ -949,7 +951,7 @@ namespace {
ref->setFunctionRefKind(functionRefKind);
auto *DSBI = cs.cacheType(new (context) DotSyntaxBaseIgnoredExpr(
base, dotLoc, ref, cs.getType(ref)));
return forceUnwrapIfExpected(DSBI, member, memberLocator);
return forceUnwrapIfExpected(DSBI, choice, memberLocator);
}

// The formal type of the 'self' value for the member's declaration.
Expand Down Expand Up @@ -1088,8 +1090,9 @@ namespace {
// We also need to handle the implicitly unwrap of the result
// of the called function if that's the type checking solution
// we ended up with.
return forceUnwrapIfExpected(ref, member, memberLocator,
member->getAttrs().hasAttribute<OptionalAttr>());
return forceUnwrapIfExpected(
ref, choice, memberLocator,
member->getAttrs().hasAttribute<OptionalAttr>());
}

// For types and properties, build member references.
Expand All @@ -1115,7 +1118,7 @@ namespace {
cs.setType(memberRefExpr, simplifyType(openedType));
Expr *result = memberRefExpr;
closeExistential(result, locator);
return forceUnwrapIfExpected(result, member, memberLocator);
return forceUnwrapIfExpected(result, choice, memberLocator);
}

// Handle all other references.
Expand All @@ -1135,7 +1138,7 @@ namespace {
ApplyExpr *apply;
if (isa<ConstructorDecl>(member)) {
// FIXME: Provide type annotation.
ref = forceUnwrapIfExpected(ref, member, memberLocator);
ref = forceUnwrapIfExpected(ref, choice, memberLocator);
apply = new (context) ConstructorRefCallExpr(ref, base);
} else if (!baseIsInstance && member->isInstanceMember()) {
// Reference to an unbound instance method.
Expand All @@ -1144,11 +1147,11 @@ namespace {
cs.getType(ref));
cs.cacheType(result);
closeExistential(result, locator, /*force=*/openedExistential);
return forceUnwrapIfExpected(result, member, memberLocator);
return forceUnwrapIfExpected(result, choice, memberLocator);
} else {
assert((!baseIsInstance || member->isInstanceMember()) &&
"can't call a static method on an instance");
ref = forceUnwrapIfExpected(ref, member, memberLocator);
ref = forceUnwrapIfExpected(ref, choice, memberLocator);
apply = new (context) DotSyntaxCallExpr(ref, dotLoc, base);
if (Implicit) {
apply->setImplicit();
Expand Down Expand Up @@ -1449,10 +1452,10 @@ namespace {
if (selected->choice.getKind() ==
OverloadChoiceKind::DynamicMemberLookup)
locatorKind = ConstraintLocator::Member;
newSubscript = forceUnwrapIfExpected(
newSubscript, selected->choice.getDecl(),
locator.withPathElement(locatorKind));

newSubscript =
forceUnwrapIfExpected(newSubscript, selected->choice,
locator.withPathElement(locatorKind));
}

return newSubscript;
Expand Down Expand Up @@ -2471,8 +2474,9 @@ namespace {
}
}

bool shouldForceUnwrapResult(Decl *decl, ConstraintLocatorBuilder locator) {
if (!decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
bool shouldForceUnwrapResult(OverloadChoice choice,
ConstraintLocatorBuilder locator) {
if (!choice.isImplicitlyUnwrappedValueOrReturnValue())
return false;

auto *choiceLocator = cs.getConstraintLocator(locator.withPathElement(
Expand All @@ -2481,10 +2485,10 @@ namespace {
return solution.getDisjunctionChoice(choiceLocator);
}

Expr *forceUnwrapIfExpected(Expr *expr, Decl *decl,
Expr *forceUnwrapIfExpected(Expr *expr, OverloadChoice choice,
ConstraintLocatorBuilder locator,
bool forForcedOptional =false) {
if (!shouldForceUnwrapResult(decl, locator))
bool forForcedOptional = false) {
if (!shouldForceUnwrapResult(choice, locator))
return expr;

// Force the expression if required for the solution.
Expand All @@ -2503,12 +2507,9 @@ namespace {
cs.setType(expr, varDecl->getType());
return expr;
}

auto choice = selected->choice;
auto decl = choice.getDecl();

return buildDeclRef(decl, expr->getNameLoc(), selected->openedFullType,
locator, expr->isImplicit(),
return buildDeclRef(selected->choice, expr->getNameLoc(),
selected->openedFullType, locator, expr->isImplicit(),
expr->getFunctionRefKind(),
expr->getAccessSemantics());
}
Expand Down Expand Up @@ -2539,9 +2540,8 @@ namespace {
auto locator = cs.getConstraintLocator(expr);
auto selected = getOverloadChoice(locator);
auto choice = selected.choice;
auto decl = choice.getDecl();

return buildDeclRef(decl, expr->getNameLoc(), selected.openedFullType,
return buildDeclRef(choice, expr->getNameLoc(), selected.openedFullType,
locator, expr->isImplicit(),
choice.getFunctionRefKind(),
AccessSemantics::Ordinary);
Expand All @@ -2566,7 +2566,7 @@ namespace {
= selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
return buildMemberRef(
expr->getBase(), selected.openedFullType, expr->getDotLoc(),
selected.choice.getDecl(), expr->getNameLoc(), selected.openedType,
selected.choice, expr->getNameLoc(), selected.openedType,
cs.getConstraintLocator(expr), memberLocator, expr->isImplicit(),
selected.choice.getFunctionRefKind(), expr->getAccessSemantics(),
isDynamic);
Expand Down Expand Up @@ -2594,7 +2594,6 @@ namespace {
auto memberLocator = cs.getConstraintLocator(
expr, ConstraintLocator::UnresolvedMember);
auto selected = getOverloadChoice(memberLocator);
auto member = selected.choice.getDecl();

// If the member came by optional unwrapping, then unwrap the base type.
if (selected.choice.getKind()
Expand All @@ -2614,7 +2613,7 @@ namespace {
bool isDynamic
= selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
auto result = buildMemberRef(
base, selected.openedFullType, expr->getDotLoc(), member,
base, selected.openedFullType, expr->getDotLoc(), selected.choice,
expr->getNameLoc(), selected.openedType,
cs.getConstraintLocator(expr), memberLocator, expr->isImplicit(),
selected.choice.getFunctionRefKind(), AccessSemantics::Ordinary,
Expand Down Expand Up @@ -2651,9 +2650,10 @@ namespace {
Expr *applyCtorRefExpr(Expr *expr, Expr *base, SourceLoc dotLoc,
DeclNameLoc nameLoc, bool implicit,
ConstraintLocator *ctorLocator,
ConstructorDecl *ctor,
FunctionRefKind functionRefKind,
Type openedType) {
OverloadChoice choice,
FunctionRefKind functionRefKind, Type openedType) {

auto *ctor = cast<ConstructorDecl>(choice.getDecl());

// If the member is a constructor, verify that it can be legally
// referenced from this base.
Expand All @@ -2665,7 +2665,7 @@ namespace {
// constructor.
if (cs.getType(base)->is<AnyMetatypeType>()) {
return buildMemberRef(
base, openedType, dotLoc, ctor, nameLoc, cs.getType(expr),
base, openedType, dotLoc, choice, nameLoc, cs.getType(expr),
ConstraintLocatorBuilder(cs.getConstraintLocator(expr)),
ctorLocator, implicit, functionRefKind, AccessSemantics::Ordinary,
/*isDynamic=*/false);
Expand Down Expand Up @@ -2731,10 +2731,9 @@ namespace {
ConstraintLocator::ConstructorMember);
if (auto selected = getOverloadChoiceIfAvailable(ctorLocator)) {
auto choice = selected->choice;
auto *ctor = cast<ConstructorDecl>(choice.getDecl());
return applyCtorRefExpr(expr, base, dotLoc, nameLoc, implicit,
ctorLocator, ctor, choice.getFunctionRefKind(),
selected->openedFullType);
return applyCtorRefExpr(
expr, base, dotLoc, nameLoc, implicit, ctorLocator, choice,
choice.getFunctionRefKind(), selected->openedFullType);
}

// Determine the declaration selected for this overloaded reference.
Expand Down Expand Up @@ -2783,11 +2782,11 @@ namespace {
case OverloadChoiceKind::DeclViaDynamic: {
bool isDynamic
= selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
return buildMemberRef(
base, selected.openedFullType, dotLoc, selected.choice.getDecl(),
nameLoc, selected.openedType, cs.getConstraintLocator(expr),
memberLocator, implicit, selected.choice.getFunctionRefKind(),
AccessSemantics::Ordinary, isDynamic);
return buildMemberRef(base, selected.openedFullType, dotLoc,
selected.choice, nameLoc, selected.openedType,
cs.getConstraintLocator(expr), memberLocator,
implicit, selected.choice.getFunctionRefKind(),
AccessSemantics::Ordinary, isDynamic);
}

case OverloadChoiceKind::TupleIndex: {
Expand Down Expand Up @@ -4370,7 +4369,7 @@ namespace {
baseTy = component.getComponentType();
resolvedComponents.push_back(component);

if (shouldForceUnwrapResult(property, locator)) {
if (shouldForceUnwrapResult(foundDecl->choice, locator)) {
auto objectTy = getObjectType(baseTy);
auto loc = origComponent.getLoc();
component = KeyPathExpr::Component::forOptionalForce(objectTy, loc);
Expand Down Expand Up @@ -4451,7 +4450,7 @@ namespace {
baseTy = component.getComponentType();
resolvedComponents.push_back(component);

if (shouldForceUnwrapResult(subscript, locator)) {
if (shouldForceUnwrapResult(foundDecl->choice, locator)) {
auto objectTy = getObjectType(baseTy);
auto loc = origComponent.getLoc();
component = KeyPathExpr::Component::forOptionalForce(objectTy, loc);
Expand Down Expand Up @@ -7469,17 +7468,16 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,

// We have the constructor.
auto choice = selected->choice;
auto decl = choice.getDecl();

// Consider the constructor decl reference expr 'implicit', but the
// constructor call expr itself has the apply's 'implicitness'.
bool isDynamic = choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
Expr *declRef =
buildMemberRef(fn, selected->openedFullType,
/*dotLoc=*/SourceLoc(), decl, DeclNameLoc(fn->getEndLoc()),
selected->openedType, locator, ctorLocator,
/*Implicit=*/true, choice.getFunctionRefKind(),
AccessSemantics::Ordinary, isDynamic);
Expr *declRef = buildMemberRef(fn, selected->openedFullType,
/*dotLoc=*/SourceLoc(), choice,
DeclNameLoc(fn->getEndLoc()),
selected->openedType, locator, ctorLocator,
/*Implicit=*/true, choice.getFunctionRefKind(),
AccessSemantics::Ordinary, isDynamic);
if (!declRef)
return nullptr;
declRef->setImplicit(apply->isImplicit());
Expand Down Expand Up @@ -8173,8 +8171,10 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
ExprRewriter rewriter(cs, solution,
/*suppressDiagnostics=*/false);

auto choice =
OverloadChoice(openedFullType, witness, FunctionRefKind::SingleApply);
auto memberRef = rewriter.buildMemberRef(
base, openedFullType, base->getStartLoc(), witness,
base, openedFullType, base->getStartLoc(), choice,
DeclNameLoc(base->getEndLoc()), openedType, dotLocator, dotLocator,
/*Implicit=*/true, FunctionRefKind::SingleApply,
AccessSemantics::Ordinary,
Expand Down
21 changes: 19 additions & 2 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,23 @@ DeclName OverloadChoice::getName() const {
}

bool OverloadChoice::isImplicitlyUnwrappedValueOrReturnValue() const {
return isDecl() &&
getDecl()->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
if (!isDecl())
return false;

auto *decl = getDecl();
if (!decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
return false;

auto itfType = decl->getInterfaceType();
if (!itfType->getAs<AnyFunctionType>())
return true;

switch (getFunctionRefKind()) {
case FunctionRefKind::Unapplied:
case FunctionRefKind::Compound:
return false;
case FunctionRefKind::SingleApply:
case FunctionRefKind::DoubleApply:
return true;
}
}
1 change: 1 addition & 0 deletions lib/Sema/OverloadChoice.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ class OverloadChoice {
result.BaseAndDeclKind.setPointer(base);
result.DeclOrKind = value;
result.DynamicNameAndFRK.setPointer(name);
result.DynamicNameAndFRK.setInt(FunctionRefKind::SingleApply);
return result;
}

Expand Down
11 changes: 11 additions & 0 deletions test/Constraints/iuo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,14 @@ func cast<T : P>(_ t: T) {
let _: (Bool) -> T? = id(T.iuoResultStatic as (Bool) -> T?)
let _: T! = id(T.iuoResultStatic(true))
}

class rdar37241550 {
public init(blah: Float) { fatalError() }
public convenience init() { fatalError() }
public convenience init!(with void: ()) { fatalError() }

static func f(_ fn: () -> rdar37241550) {}
static func test() {
f(rdar37241550.init) // no error, the failable init is not applicable
}
}