# The correct way to build an implicit callExpr from a optional base

**URL:** <https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638>\
**Category:** Compiler\
**Created:** [August 29, 2018, 6:12pm UTC](https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638 "2018-08-29T18:12:22Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![anthonylatsis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anthonylatsis/32/39232_2.png) [@anthonylatsis](https://forums.swift.org/u/anthonylatsis)\
**Post date:** [August 29, 2018, 6:12pm UTC](https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638/1 "2018-08-29T18:12:22Z")

</div>

Let us have

```swift
let array: [Int]? = [0]

```

I need to build `array?.makeIterator()` out of `array` for later use. Normally it would be `array.makeIterator()`, but I need optional chaining because I expect an optional sequence. How to build it if `array` were not optional is described in [TypeChecker::callWitness](https://github.com/apple/swift/blob/b3a3220e388d937023a950f59b0c3e350d5e0652/lib/Sema/CSApply.cpp#L7861) with a couple of fixits.

This is the basic workflow I have based on what's in `callWitness`.

```cpp
auto BOE = new (Context) BindOptionalExpr(base, base->getEndLoc(), 0);

auto UDE = new (Context) UnresolvedDotExpr(
  BOE, SourceLoc(), witness.getDecl()->getFullName(),
  DeclNameLoc(BOE->getEndLoc()), /*Implicit=*/true);

unresolvedDot->setFunctionRefKind(FunctionRefKind::SingleApply);
auto dotLocator = cs.getConstraintLocator(unresolvedDot);

Type openedFullType, openedType;
std::tie(openedFullType, openedType)
  = cs.getTypeOfMemberReference(base->getType(), witness.getDecl(), dc, 
                                /*isDynamicResult=*/false,
                                FunctionRefKind::DoubleApply,
                                dotLocator);

auto getType = [&](const Expr *E) -> Type {
    return cs.getType(E);
};

auto call = CallExpr::create(Context, UDE, base->getStartLoc(), arguments,
                             argLabels, {}, base->getEndLoc(),
                             /*trailingClosure=*/nullptr,
                             /*implicit=*/true, getType);

auto OEE = new (Context) OptionalEvaluationExpr(call);
cs.cacheSubExprTypes(OEE);

auto openedFuncType = openedType->castTo<FunctionType>();

cs.addConstraint(
  ConstraintKind::ArgumentTupleConversion, cs.getType(call->getArg()),
  FunctionType::composeInput(cs.getASTContext(),
                             openedFuncType->getParams(), false),
                             cs.getConstraintLocator(call, ConstraintLocator::ApplyArgument));

// solve the CS.

```

The constraint system before solving it:

```swift
Type Variables:
  $T0 as [Int]?
Active Constraints:
  $T0 conforms to Collection
  $T0.Iterator equal IndexingIterator<$T0>

```

The main problem is this `$T0 conforms to Collection` constraint that is added by `getTypeOfMemberReference` and makes everything break.  
If I pass `base->getType()->getOptionalObjectType()` to `getTypeOfMemberReference` instead, it's a bit better since `T0` becomes `[Int]`, but still crashes on an unhandled coercion further on.

P.S. Judging from [this](https://github.com/apple/swift/blob/b3a3220e388d937023a950f59b0c3e350d5e0652/lib/Sema/CSApply.cpp#L7891) comment, this approach is more of a hack, and a bad one – I would be glad to learn the proper way of doing whatever the comment refers to.

@rudkx @Slava_Pestov @Douglas_Gregor

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [September 4, 2018, 8:27pm UTC](https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638/2 "2018-09-04T20:27:44Z")

</div>

Take a look at OptionalEvaluationExpr and BindOptionalExpr. You want to use the BindOptionalExpr as the 'base" for your member lookup.

---

<div class="post-metadata">

**Author:** ![anthonylatsis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anthonylatsis/32/39232_2.png) [@anthonylatsis](https://forums.swift.org/u/anthonylatsis)\
**Post date:** [September 4, 2018, 8:46pm UTC](https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638/3 "2018-09-04T20:46:57Z")

</div>

Ah, so member lookup with an optional base considers the object type's members as well. Thank you!

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [September 4, 2018, 9:05pm UTC](https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638/4 "2018-09-04T21:05:08Z")

</div>

> [@anthonylatsis](#):
>
> Ah, so member lookup with an optional base considers the object type's members as well. Thank you!

No, that is not correct. Optional evaluation, like foo?.bar(), is modeled as an OptionalEvaluationExpr that takes 'foo', of Optional type. The member access itself is performed on the BindOptionalExpr, which has non-optional type -- it represents the unwrapped value.

---

<div class="post-metadata">

**Author:** ![anthonylatsis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anthonylatsis/32/39232_2.png) [@anthonylatsis](https://forums.swift.org/u/anthonylatsis)\
**Post date:** [September 4, 2018, 9:37pm UTC](https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638/5 "2018-09-04T21:37:56Z")

</div>

I am already modeling it this way in the code snippet up there. Do you mean to enclose my `array` declaration reference expression with optional type in a `BindOptionalExpr` _before_ calling `callWitness`, then pass that as the base so that everything happens "as if `array` isn't optional" and finally enclose it in an `OptionalEvaluationExpr` after returning? I'm not sure where to perform type-checking for that part though.

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [September 4, 2018, 9:48pm UTC](https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638/6 "2018-09-04T21:48:44Z")

</div>

The base expression you pass to cs.getTypeOfMemberReference() should be the BindOptionalExpr, not 'base', I think.

> I'm not sure where to perform type-checking for that part though.

I'm assuming you're working on something in CSApply.cpp. Please try to build fully type-checked AST here, instead of calling typeCheckExpression() again. Also note that callWitness() is likely to be radically simplified or removed altogether at some point.

---

<div class="post-metadata">

**Author:** ![anthonylatsis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anthonylatsis/32/39232_2.png) [@anthonylatsis](https://forums.swift.org/u/anthonylatsis)\
**Post date:** [September 4, 2018, 10:06pm UTC](https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638/7 "2018-09-04T22:06:15Z")

</div>

The problem is that `cs.getTypeOfMemberReference()` takes a type, not an expression, but I've got a few ideas. Of course, I'll make sure everything is being type-checked. Thank you.

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [September 4, 2018, 10:08pm UTC](https://forums.swift.org/t/the-correct-way-to-build-an-implicit-callexpr-from-a-optional-base/15638/8 "2018-09-04T22:08:21Z")

</div>

> [@anthonylatsis](#):
>
> The problem is that `cs.getTypeOfMemberReference()` takes a type, not an expression, but I've got a few ideas.

Right, you pass in the type of the BindOptionalExpr, which is the unwrapped non-optional type you're actually doing the lookup into.
