Merge pull request #20693 from xedin/forward-autoclosure-diagnostic

[CSDiagnostics] Add custom diagnostic for invalid @autoclosure forwarding
diff --git a/include/swift/Sema/IDETypeChecking.h b/include/swift/Sema/IDETypeChecking.h
index 1f2c057..c55dbce 100644
--- a/include/swift/Sema/IDETypeChecking.h
+++ b/include/swift/Sema/IDETypeChecking.h
@@ -98,19 +98,16 @@
                    Expr *&parsedExpr,
                    ConcreteDeclRef &referencedDecl);
 
-  /// Typecheck the sequence expression \p parsedExpr for code completion.
+  /// Resolve type of operator function with \c opName appending it to \c LHS.
   ///
-  /// This requires that \p parsedExpr is a SequenceExpr and that it contains:
-  ///   * ... leading sequence  LHS
-  ///   * UnresolvedDeclRefExpr operator
-  ///   * CodeCompletionExpr    RHS
-  ///
-  /// On success, returns false, and replaces parsedExpr with the binary
-  /// expression corresponding to the operator.  The type of the operator and
-  /// RHS are also set, but the rest of the expression may not be typed
-  ///
-  /// The LHS should already be type-checked or this will be very slow.
-  bool typeCheckCompletionSequence(DeclContext *DC, Expr *&parsedExpr);
+  /// For \p refKind, use \c DeclRefKind::PostfixOperator for postfix operator,
+  /// or \c DeclRefKind::BinaryOperator for infix operator.
+  /// On success, returns resolved function type of the operator. The LHS should
+  /// already be type-checked. This function guarantees LHS not to be modified.
+  FunctionType *getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
+                                            Identifier opName,
+                                            DeclRefKind refKind,
+                                            ConcreteDeclRef &referencedDecl);
 
   /// Typecheck the given expression.
   bool typeCheckExpression(DeclContext *DC, Expr *&parsedExpr);
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index ba6bfc0..6847272 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -1261,10 +1261,12 @@
 
   std::unique_ptr<llvm::raw_fd_ostream> OptRecordFile =
       createOptRecordFile(SILOpts.OptRecordFile, Instance.getDiags());
-  if (OptRecordFile)
-    SM->setOptRecordStream(llvm::make_unique<llvm::yaml::Output>(
-                               *OptRecordFile, &Instance.getSourceMgr()),
-                           std::move(OptRecordFile));
+  if (OptRecordFile) {
+    auto Output =
+        llvm::make_unique<llvm::yaml::Output>(*OptRecordFile,
+                                              &Instance.getSourceMgr());
+    SM->setOptRecordStream(std::move(Output), std::move(OptRecordFile));
+  }
 
   if (performMandatorySILPasses(Invocation, SM.get(), observer))
     return true;
diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp
index 6be2f80..8be5875 100644
--- a/lib/IDE/CodeCompletion.cpp
+++ b/lib/IDE/CodeCompletion.cpp
@@ -3291,35 +3291,15 @@
   }
 
   void tryPostfixOperator(Expr *expr, PostfixOperatorDecl *op) {
-    auto Ty = expr->getType();
-    if (!Ty)
+    ConcreteDeclRef referencedDecl;
+    FunctionType *funcTy = getTypeOfCompletionOperator(
+        const_cast<DeclContext *>(CurrDeclContext), expr, op->getName(),
+        DeclRefKind::PostfixOperator, referencedDecl);
+    if (!funcTy)
       return;
 
-    SWIFT_DEFER {
-      // Restore type.
-      // FIXME: This is workaround for getTypeOfExpressionWithoutApplying()
-      // modifies type of 'expr'.
-      expr->setType(Ty);
-      prepareForRetypechecking(expr);
-    };
-
-    // We allocate these expressions on the stack because we know they can't
-    // escape and there isn't a better way to allocate scratch Expr nodes.
-    UnresolvedDeclRefExpr UDRE(op->getName(), DeclRefKind::PostfixOperator,
-                               DeclNameLoc(expr->getSourceRange().End));
-    ParenExpr parenExpr(expr->getSourceRange().Start, expr,
-                        expr->getSourceRange().End,
-                        /*hasTrailingClosure=*/false);
-    PostfixUnaryExpr opExpr(&UDRE, &parenExpr);
-    Expr *tempExpr = &opExpr;
-    ConcreteDeclRef referencedDecl;
-    if (auto T = getTypeOfCompletionContextExpr(
-            CurrDeclContext->getASTContext(),
-            const_cast<DeclContext *>(CurrDeclContext),
-            CompletionTypeCheckKind::Normal,
-            tempExpr,
-            referencedDecl))
-      addPostfixOperatorCompletion(op, *T);
+    // TODO: Use referencedDecl (FuncDecl) instead of 'op' (OperatorDecl).
+    addPostfixOperatorCompletion(op, funcTy->getResult());
   }
 
   void addAssignmentOperator(Type RHSType, Type resultType) {
@@ -3366,169 +3346,67 @@
       addTypeAnnotation(builder, resultType);
   }
 
-  void tryInfixOperatorCompletion(InfixOperatorDecl *op, SequenceExpr *SE) {
-    if (op->getName().str() == "~>")
+  void tryInfixOperatorCompletion(Expr *foldedExpr, InfixOperatorDecl *op) {
+    ConcreteDeclRef referencedDecl;
+    FunctionType *funcTy = getTypeOfCompletionOperator(
+        const_cast<DeclContext *>(CurrDeclContext), foldedExpr, op->getName(),
+        DeclRefKind::BinaryOperator, referencedDecl);
+    if (!funcTy)
       return;
 
-    MutableArrayRef<Expr *> sequence = SE->getElements();
-    assert(sequence.size() >= 3 && !sequence.back() &&
-           !sequence.drop_back(1).back() && "sequence not cleaned up");
-    assert((sequence.size() & 1) && "sequence expr ending with operator");
+    Type lhsTy = funcTy->getParams()[0].getPlainType();
+    Type rhsTy = funcTy->getParams()[1].getPlainType();
+    Type resultTy = funcTy->getResult();
 
-    // FIXME: these checks should apply to the LHS of the operator, not the
-    // immediately left expression.  Move under the type-checking.
-    Expr *LHS = sequence.drop_back(2).back();
-    if (LHS->getType() && (LHS->getType()->is<MetatypeType>() ||
-                           LHS->getType()->is<AnyFunctionType>()))
-      return;
-
-    // Preserve LHS type for restoring it.
-    Type LHSTy = LHS->getType();
-
-    // We allocate these expressions on the stack because we know they can't
-    // escape and there isn't a better way to allocate scratch Expr nodes.
-    UnresolvedDeclRefExpr UDRE(op->getName(), DeclRefKind::BinaryOperator,
-                               DeclNameLoc(LHS->getEndLoc()));
-    sequence.drop_back(1).back() = &UDRE;
-    CodeCompletionExpr CCE(LHS->getSourceRange());
-    sequence.back() = &CCE;
-
-    SWIFT_DEFER {
-      // Reset sequence.
-      SE->setElement(SE->getNumElements() - 1, nullptr);
-      SE->setElement(SE->getNumElements() - 2, nullptr);
-      LHS->setType(LHSTy);
-      prepareForRetypechecking(SE);
-
-      for (auto &element : sequence.drop_back(2)) {
-        // Unfold expressions for re-typechecking sequence.
-        if (auto *assignExpr = dyn_cast_or_null<AssignExpr>(element)) {
-          assignExpr->setSrc(nullptr);
-          assignExpr->setDest(nullptr);
-        } else if (auto *ifExpr = dyn_cast_or_null<IfExpr>(element)) {
-          ifExpr->setCondExpr(nullptr);
-          ifExpr->setElseExpr(nullptr);
-        }
-
-        // Reset any references to operators in types, so they are properly
-        // handled as operators by sequence folding.
-        //
-        // FIXME: Would be better to have some kind of 'OperatorRefExpr'?
-        if (auto operatorRef = element->getMemberOperatorRef()) {
-          operatorRef->setType(nullptr);
-          element = operatorRef;
-        }
-      }
-    };
-
-    Expr *expr = SE;
-    if (!typeCheckCompletionSequence(const_cast<DeclContext *>(CurrDeclContext),
-                                     expr)) {
-      if (!LHS->getType() ||
-          !LHS->getType()->getRValueType()->getOptionalObjectType()) {
-        // Don't complete optional operators on non-optional types.
-        // FIXME: can we get the type-checker to disallow these for us?
-        if (op->getName().str() == "??")
-          return;
-        if (auto NT = CCE.getType()->getNominalOrBoundGenericNominal()) {
-          if (NT->getName() ==
-              CurrDeclContext->getASTContext().Id_OptionalNilComparisonType)
-            return;
-        }
-      }
-
-      // If the right-hand side and result type are both type parameters, we're
-      // not providing a useful completion.
-      if (expr->getType()->isTypeParameter() &&
-          CCE.getType()->isTypeParameter())
+    // Don't complete optional operators on non-optional types.
+    if (!lhsTy->getRValueType()->getOptionalObjectType()) {
+      // 'T ?? T'
+      if (op->getName().str() == "??")
         return;
-
-      addInfixOperatorCompletion(op, expr->getType(), CCE.getType());
+      // 'T == nil'
+      if (auto NT = rhsTy->getNominalOrBoundGenericNominal())
+        if (NT->getName() ==
+            CurrDeclContext->getASTContext().Id_OptionalNilComparisonType)
+          return;
     }
+
+    // If the right-hand side and result type are both type parameters, we're
+    // not providing a useful completion.
+    if (resultTy->isTypeParameter() && rhsTy->isTypeParameter())
+      return;
+
+    // TODO: Use referencedDecl (FuncDecl) instead of 'op' (OperatorDecl).
+    addInfixOperatorCompletion(op, funcTy->getResult(),
+                               funcTy->getParams()[1].getPlainType());
   }
 
-  void flattenBinaryExpr(Expr *expr, SmallVectorImpl<Expr *> &sequence) {
-    if (auto binExpr = dyn_cast<BinaryExpr>(expr)) {
-      flattenBinaryExpr(binExpr->getArg()->getElement(0), sequence);
-      sequence.push_back(binExpr->getFn());
-      flattenBinaryExpr(binExpr->getArg()->getElement(1), sequence);
-    } else if (auto assignExpr = dyn_cast<AssignExpr>(expr)) {
-      flattenBinaryExpr(assignExpr->getDest(), sequence);
-      sequence.push_back(assignExpr);
-      flattenBinaryExpr(assignExpr->getSrc(), sequence);
-      assignExpr->setDest(nullptr);
-      assignExpr->setSrc(nullptr);
-    } else if (auto ifExpr = dyn_cast<IfExpr>(expr)) {
-      flattenBinaryExpr(ifExpr->getCondExpr(), sequence);
-      sequence.push_back(ifExpr);
-      flattenBinaryExpr(ifExpr->getElseExpr(), sequence);
-      ifExpr->setCondExpr(nullptr);
-      ifExpr->setElseExpr(nullptr);
-    } else if (auto tryExpr = dyn_cast<AnyTryExpr>(expr)) {
-      // Strip out try expression. It doesn't affect completion.
-      flattenBinaryExpr(tryExpr->getSubExpr(), sequence);
-    } else if (auto optEval = dyn_cast<OptionalEvaluationExpr>(expr)){
-      // Strip out optional evaluation expression. It doesn't affect completion.
-      flattenBinaryExpr(optEval->getSubExpr(), sequence);
-    } else {
-      sequence.push_back(expr);
-    }
-  }
+  Expr *typeCheckLeadingSequence(Expr *LHS, ArrayRef<Expr *> leadingSequence) {
+    if (leadingSequence.empty())
+      return LHS;
 
-  void typeCheckLeadingSequence(SmallVectorImpl<Expr *> &sequence) {
-
-    // Strip out try and optional evaluation expr because foldSequence() mutates
-    // hierarchy of these expressions. They don't affect completion anyway.
-    for (auto &element : sequence) {
-      if (auto *tryExpr = dyn_cast<AnyTryExpr>(element))
-        element = tryExpr->getSubExpr();
-      if (auto *optEval = dyn_cast<OptionalEvaluationExpr>(element))
-        element = optEval->getSubExpr();
-    }
+    assert(leadingSequence.size() % 2 == 0);
+    SmallVector<Expr *, 3> sequence(leadingSequence.begin(),
+                                    leadingSequence.end());
+    sequence.push_back(LHS);
 
     Expr *expr =
         SequenceExpr::create(CurrDeclContext->getASTContext(), sequence);
     prepareForRetypechecking(expr);
-    // Take advantage of the fact the type-checker leaves the types on the AST.
     if (!typeCheckExpression(const_cast<DeclContext *>(CurrDeclContext),
                              expr)) {
-      // Rebuild the sequence from the type-checked version.
-      sequence.clear();
-      flattenBinaryExpr(expr, sequence);
-      return;
+      return expr;
     }
-
-    // Fall back to just using the immediate LHS.
-    auto LHS = sequence.back();
-    sequence.clear();
-    sequence.push_back(LHS);
+    return LHS;
   }
 
   void getOperatorCompletions(Expr *LHS, ArrayRef<Expr *> leadingSequence) {
-    std::vector<OperatorDecl *> operators = collectOperators();
+    Expr *foldedExpr = typeCheckLeadingSequence(LHS, leadingSequence);
 
+    std::vector<OperatorDecl *> operators = collectOperators();
     // FIXME: this always chooses the first operator with the given name.
     llvm::DenseSet<Identifier> seenPostfixOperators;
     llvm::DenseSet<Identifier> seenInfixOperators;
 
-    SmallVector<Expr *, 3> sequence(leadingSequence.begin(),
-                                    leadingSequence.end());
-    sequence.push_back(LHS);
-    assert((sequence.size() & 1) && "sequence expr ending with operator");
-
-    if (sequence.size() > 1)
-      typeCheckLeadingSequence(sequence);
-
-    // Retrieve typechecked LHS.
-    LHS = sequence.back();
-
-    // Create a single sequence expression, which we will modify for each
-    // operator, filling in the operator and dummy right-hand side.
-    sequence.push_back(nullptr); // operator
-    sequence.push_back(nullptr); // RHS
-    auto *SE = SequenceExpr::create(CurrDeclContext->getASTContext(), sequence);
-    prepareForRetypechecking(SE);
-
     for (auto op : operators) {
       switch (op->getKind()) {
       case DeclKind::PrefixOperator:
@@ -3541,7 +3419,7 @@
         break;
       case DeclKind::InfixOperator:
         if (seenInfixOperators.insert(op->getName()).second)
-          tryInfixOperatorCompletion(cast<InfixOperatorDecl>(op), SE);
+          tryInfixOperatorCompletion(foldedExpr, cast<InfixOperatorDecl>(op));
         break;
       default:
         llvm_unreachable("unexpected operator kind");
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 5feff4b..238cac9 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -1233,7 +1233,7 @@
     sectionName = "swift5_replace";
     break;
   case llvm::Triple::COFF:
-    sectionName = ".sw5repl";
+    sectionName = ".sw5repl$B";
     break;
   default:
     llvm_unreachable("Don't know how to emit field records table for "
@@ -3539,6 +3539,8 @@
 llvm::Constant *IRGenModule::getAddrOfProtocolConformanceDescriptor(
                                 const RootProtocolConformance *conformance,
                                 ConstantInit definition) {
+  IRGen.addLazyWitnessTable(conformance);
+
   auto entity = LinkEntity::forProtocolConformanceDescriptor(conformance);
   return getAddrOfLLVMVariable(entity, definition,
                                DebugTypeInfo());
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index 16cf4cd..8e7159d 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -127,14 +127,20 @@
   class LinkedExprCollector : public ASTWalker {
     
     llvm::SmallVectorImpl<Expr*> &LinkedExprs;
+    ConstraintSystem &CS;
 
   public:
-    
-    LinkedExprCollector(llvm::SmallVectorImpl<Expr*> &linkedExprs) :
-        LinkedExprs(linkedExprs) {}
-    
+    LinkedExprCollector(llvm::SmallVectorImpl<Expr *> &linkedExprs,
+                        ConstraintSystem &cs)
+        : LinkedExprs(linkedExprs), CS(cs) {}
+
     std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
-      
+
+      if (CS.shouldReusePrecheckedType() &&
+          !CS.getType(expr)->hasTypeVariable()) {
+        return { false, expr };
+      }
+
       // Store top-level binary exprs for further analysis.
       if (isa<BinaryExpr>(expr) ||
           
@@ -195,6 +201,11 @@
         LTI(lti), CS(cs) {}
     
     std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
+
+      if (CS.shouldReusePrecheckedType() &&
+          !CS.getType(expr)->hasTypeVariable()) {
+        return { false, expr };
+      }
       
       if (isa<IntegerLiteralExpr>(expr)) {
         LTI.haveIntLiteral = true;
@@ -934,6 +945,11 @@
       CS(cs) {}
     
     std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
+
+      if (CS.shouldReusePrecheckedType() &&
+          !CS.getType(expr)->hasTypeVariable()) {
+        return { false, expr };
+      }
       
       if (auto applyExpr = dyn_cast<ApplyExpr>(expr)) {
         if (isa<PrefixUnaryExpr>(applyExpr) ||
@@ -3240,6 +3256,12 @@
 
     std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
       while (true) {
+
+        // If we should reuse pre-checked types, don't sanitize the expression
+        // if it's already type-checked.
+        if (CS.shouldReusePrecheckedType() && expr->getType())
+          return { false, expr };
+
         // OpenExistentialExpr contains OpaqueValueExpr in its sub expression.
         if (auto OOE = dyn_cast<OpenExistentialExpr>(expr)) {
           auto archetypeVal = OOE->getOpaqueValue();
@@ -3409,6 +3431,15 @@
     ConstraintWalker(ConstraintGenerator &CG) : CG(CG) { }
 
     std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
+
+      if (CG.getConstraintSystem().shouldReusePrecheckedType()) {
+        if (expr->getType()) {
+          assert(!expr->getType()->hasTypeVariable());
+          CG.getConstraintSystem().cacheType(expr);
+          return { false, expr };
+        }
+      }
+
       // Note that the subexpression of a #selector expression is
       // unevaluated.
       if (auto sel = dyn_cast<ObjCSelectorExpr>(expr)) {
@@ -3629,7 +3660,7 @@
   SmallVector<Expr *, 16> linkedExprs;
   
   // Collect any linked expressions.
-  LinkedExprCollector collector(linkedExprs);
+  LinkedExprCollector collector(linkedExprs, *this);
   e->walk(collector);
   
   // Favor types, as appropriate.
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index 62066d7..a252195 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -823,6 +823,10 @@
   /// system is not applied to the expression AST, but the ConstraintSystem is
   /// left in-tact.
   AllowUnresolvedTypeVariables = 0x10,
+
+  /// If set, constraint system always reuses type of pre-typechecked
+  /// expression, and doesn't dig into its subexpressions.
+  ReusePrecheckedType = 0x20,
 };
 
 /// Options that affect the constraint system as a whole.
@@ -1779,17 +1783,21 @@
 public:
 
   /// \brief Whether we should attempt to fix problems.
-  bool shouldAttemptFixes() {
+  bool shouldAttemptFixes() const {
     if (!(Options & ConstraintSystemFlags::AllowFixes))
       return false;
 
     return !solverState || solverState->recordFixes;
   }
 
-  bool shouldSuppressDiagnostics() {
+  bool shouldSuppressDiagnostics() const {
     return Options.contains(ConstraintSystemFlags::SuppressDiagnostics);
   }
 
+  bool shouldReusePrecheckedType() const {
+    return Options.contains(ConstraintSystemFlags::ReusePrecheckedType);
+  }
+
   /// \brief Log and record the application of the fix. Return true iff any
   /// subsequent solution would be worse than the best known solution.
   bool recordFix(ConstraintFix *fix);
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index 1410e8e..4e7365a 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -2220,57 +2220,26 @@
   }
 }
 
-bool TypeChecker::typeCheckCompletionSequence(Expr *&expr, DeclContext *DC) {
-  FrontendStatsTracer StatsTracer(Context.Stats, "typecheck-completion-seq", expr);
+static FunctionType *
+getTypeOfCompletionOperatorImpl(TypeChecker &TC, DeclContext *DC, Expr *expr,
+                                ConcreteDeclRef &referencedDecl) {
+  ASTContext &Context = TC.Context;
+
+  FrontendStatsTracer StatsTracer(Context.Stats,
+                                  "typecheck-completion-operator", expr);
   PrettyStackTraceExpr stackTrace(Context, "type-checking", expr);
 
+  ConstraintSystemOptions options;
+  options |= ConstraintSystemFlags::SuppressDiagnostics;
+  options |= ConstraintSystemFlags::ReusePrecheckedType;
+
   // Construct a constraint system from this expression.
-  ConstraintSystem CS(*this, DC, ConstraintSystemFlags::SuppressDiagnostics);
+  ConstraintSystem CS(TC, DC, options);
+  expr = CS.generateConstraints(expr);
+  if (!expr)
+    return nullptr;
 
-  auto *SE = cast<SequenceExpr>(expr);
-  assert(SE->getNumElements() >= 3);
-  auto *op = SE->getElement(SE->getNumElements() - 2);
-  auto *CCE = cast<CodeCompletionExpr>(SE->getElements().back());
-
-  // Resolve the op.
-  op = resolveDeclRefExpr(cast<UnresolvedDeclRefExpr>(op), DC);
-  SE->setElement(SE->getNumElements() - 2, op);
-
-  // Fold the sequence.
-  expr = foldSequence(SE, DC);
-
-  // Find the code-completion expression and operator again.
-  Expr *exprAsBinOp = nullptr;
-  while (true) {
-    Expr *RHS;
-    if (auto *binExpr = dyn_cast<BinaryExpr>(expr))
-      RHS = binExpr->getArg()->getElement(1);
-    else if (auto *assignExpr = dyn_cast<AssignExpr>(expr))
-      RHS = assignExpr->getSrc();
-    else if (auto *ifExpr = dyn_cast<IfExpr>(expr))
-      RHS = ifExpr->getElseExpr();
-    else
-      break;
-
-    if (RHS == CCE) {
-      exprAsBinOp = expr;
-      break;
-    }
-    expr = RHS;
-  }
-  if (!exprAsBinOp)
-    return true;
-
-  // Ensure the output expression is up to date.
-  assert(exprAsBinOp == expr && isa<BinaryExpr>(expr) && "found wrong expr?");
-
-  if (auto generated = CS.generateConstraints(expr)) {
-    expr = generated;
-  } else {
-    return true;
-  }
-
-  if (getLangOpts().DebugConstraintSolver) {
+  if (TC.getLangOpts().DebugConstraintSolver) {
     auto &log = Context.TypeCheckerDebug->getStream();
     log << "---Initial constraints for the given expression---\n";
     expr->dump(log);
@@ -2281,20 +2250,100 @@
   // Attempt to solve the constraint system.
   SmallVector<Solution, 4> viable;
   if (CS.solve(expr, viable, FreeTypeVariableBinding::Disallow))
-    return true;
+    return nullptr;
 
   auto &solution = viable[0];
-  if (getLangOpts().DebugConstraintSolver) {
+  if (TC.getLangOpts().DebugConstraintSolver) {
     auto &log = Context.TypeCheckerDebug->getStream();
     log << "---Solution---\n";
     solution.dump(log);
   }
 
-  auto &solutionCS = solution.getConstraintSystem();
-  expr->setType(solution.simplifyType(solutionCS.getType(expr)));
-  auto completionType = solution.simplifyType(solutionCS.getType(CCE));
-  CCE->setType(completionType);
-  return false;
+  // Fill the results.
+  Expr *opExpr = cast<ApplyExpr>(expr)->getFn();
+  referencedDecl =
+      solution.resolveLocatorToDecl(CS.getConstraintLocator(opExpr));
+
+  // Return '(ArgType[, ArgType]) -> ResultType' as a function type.
+  // We don't use the type of the operator expression because we want the types
+  // of the *arguments* instead of the types of the parameters.
+  Expr *argsExpr = cast<ApplyExpr>(expr)->getArg();
+  SmallVector<FunctionType::Param, 2> argTypes;
+  if (auto *PE = dyn_cast<ParenExpr>(argsExpr)) {
+    argTypes.emplace_back(solution.simplifyType(CS.getType(PE->getSubExpr())));
+  } else if (auto *TE = dyn_cast<TupleExpr>(argsExpr)) {
+    for (auto arg : TE->getElements())
+      argTypes.emplace_back(solution.simplifyType(CS.getType(arg)));
+  }
+
+  return FunctionType::get(argTypes, solution.simplifyType(CS.getType(expr)));
+}
+
+/// \brief Return the type of operator function for specified LHS, or a null
+/// \c Type on error.
+FunctionType *
+TypeChecker::getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
+                                         Identifier opName, DeclRefKind refKind,
+                                         ConcreteDeclRef &referencedDecl) {
+
+  // For the infix operator, find the actual LHS from pre-folded LHS.
+  if (refKind == DeclRefKind::BinaryOperator)
+    LHS = findLHS(DC, LHS, opName);
+
+  if (!LHS)
+    return nullptr;
+
+  auto LHSTy = LHS->getType();
+
+  // FIXME: 'UnresolvedType' still might be typechecked by an operator.
+  if (!LHSTy || LHSTy->is<UnresolvedType>())
+    return nullptr;
+
+  // Meta types and function types cannot be a operand of operator expressions.
+  if (LHSTy->is<MetatypeType>() || LHSTy->is<AnyFunctionType>())
+    return nullptr;
+
+  auto Loc = LHS->getEndLoc();
+
+  // Build temporary expression to typecheck.
+  // We allocate these expressions on the stack because we know they can't
+  // escape and there isn't a better way to allocate scratch Expr nodes.
+  UnresolvedDeclRefExpr UDRE(opName, refKind, DeclNameLoc(Loc));
+  auto *opExpr = resolveDeclRefExpr(&UDRE, DC);
+
+  switch (refKind) {
+
+  case DeclRefKind::PostfixOperator: {
+    // (postfix_unary_expr
+    //   (declref_expr name=<opName>)
+    //   (paren_expr
+    //     (<LHS>)))
+    ParenExpr Args(SourceLoc(), LHS, SourceLoc(),
+                   /*hasTrailingClosure=*/false);
+    PostfixUnaryExpr postfixExpr(opExpr, &Args);
+    return getTypeOfCompletionOperatorImpl(*this, DC, &postfixExpr,
+                                           referencedDecl);
+  }
+
+  case DeclRefKind::BinaryOperator: {
+    // (binary_expr
+    //   (declref_expr name=<opName>)
+    //   (tuple_expr
+    //     (<LHS>)
+    //     (code_completion_expr)))
+    CodeCompletionExpr dummyRHS(Loc);
+    auto Args = TupleExpr::create(
+        Context, SourceLoc(), {LHS, &dummyRHS}, {}, {}, SourceLoc(),
+        /*hasTrailingClosure=*/false, /*isImplicit=*/true);
+    BinaryExpr binaryExpr(opExpr, Args, /*isImplicit=*/true);
+
+    return getTypeOfCompletionOperatorImpl(*this, DC, &binaryExpr,
+                                           referencedDecl);
+  }
+
+  default:
+    llvm_unreachable("Invalid DeclRefKind for operator completion");
+  }
 }
 
 bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp
index 15786b8..33e86e1 100644
--- a/lib/Sema/TypeCheckExpr.cpp
+++ b/lib/Sema/TypeCheckExpr.cpp
@@ -190,6 +190,15 @@
     return lookupPrecedenceGroupForInfixOperator(DC, binaryExpr->getFn());
   }
 
+  if (auto *DSCE = dyn_cast<DotSyntaxCallExpr>(E)) {
+    return lookupPrecedenceGroupForInfixOperator(DC, DSCE->getFn());
+  }
+
+  if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
+    Identifier name = MRE->getDecl().getDecl()->getBaseName().getIdentifier();
+    return lookupPrecedenceGroupForOperator(*this, DC, name, MRE->getLoc());
+  }
+
   // If E is already an ErrorExpr, then we've diagnosed it as invalid already,
   // otherwise emit an error.
   if (!isa<ErrorExpr>(E))
@@ -198,6 +207,58 @@
   return nullptr;
 }
 
+/// Find LHS as if we append binary operator to existing pre-folded expresion.
+/// Returns found expression, or \c nullptr if the operator is not applicable.
+///
+/// For example, given '(== R (* A B))':
+/// 'findLHS(DC, expr, "+")' returns '(* A B)'.
+/// 'findLHS(DC, expr, "<<")' returns 'B'.
+/// 'findLHS(DC, expr, '==')' returns nullptr.
+Expr *TypeChecker::findLHS(DeclContext *DC, Expr *E, Identifier name) {
+  auto right = lookupPrecedenceGroupForOperator(*this, DC, name, E->getEndLoc());
+  while (true) {
+
+    // Look through implicit conversions.
+    if (auto ICE = dyn_cast<ImplicitConversionExpr>(E)) {
+      E = ICE->getSyntacticSubExpr();
+      continue;
+    }
+    if (auto ACE = dyn_cast<AutoClosureExpr>(E)) {
+      E = ACE->getSingleExpressionBody();
+      continue;
+    }
+
+    auto left = lookupPrecedenceGroupForInfixOperator(DC, E);
+    if (!left)
+      // LHS is not binary expression.
+      return E;
+    switch (Context.associateInfixOperators(left, right)) {
+      case swift::Associativity::None:
+        return nullptr;
+      case swift::Associativity::Left:
+        return E;
+      case swift::Associativity::Right:
+        break;
+    }
+    // Find the RHS of the current binary expr.
+    if (auto *assignExpr = dyn_cast<AssignExpr>(E)) {
+      E = assignExpr->getSrc();
+    } else if (auto *ifExpr = dyn_cast<IfExpr>(E)) {
+      E = ifExpr->getElseExpr();
+    } else if (auto *binaryExpr = dyn_cast<BinaryExpr>(E)) {
+      auto *Args = dyn_cast<TupleExpr>(binaryExpr->getArg());
+      if (!Args || Args->getNumElements() != 2)
+        return nullptr;
+      E = Args->getElement(1);
+    } else {
+      // E.g. 'fn() as Int << 2'.
+      // In this case '<<' has higher precedence than 'as', but the LHS should
+      // be 'fn() as Int' instead of 'Int'.
+      return E;
+    }
+  }
+}
+
 // The way we compute isEndOfSequence relies on the assumption that
 // the sequence-folding algorithm never recurses with a prefix of the
 // entire sequence.
diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp
index 504766f..ba604a8 100644
--- a/lib/Sema/TypeChecker.cpp
+++ b/lib/Sema/TypeChecker.cpp
@@ -840,11 +840,17 @@
                                           referencedDecl);
 }
 
-bool swift::typeCheckCompletionSequence(DeclContext *DC, Expr *&parsedExpr) {
+/// \brief Return the type of operator function for specified LHS, or a null
+/// \c Type on error.
+FunctionType *
+swift::getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
+                                   Identifier opName, DeclRefKind refKind,
+                                   ConcreteDeclRef &referencedDecl) {
   auto &ctx = DC->getASTContext();
   DiagnosticSuppression suppression(ctx.Diags);
   TypeChecker &TC = createTypeChecker(ctx);
-  return TC.typeCheckCompletionSequence(parsedExpr, DC);
+  return TC.getTypeOfCompletionOperator(DC, LHS, opName, refKind,
+                                        referencedDecl);
 }
 
 bool swift::typeCheckExpression(DeclContext *DC, Expr *&parsedExpr) {
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index ff6f076..8ee715b 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -1404,7 +1404,12 @@
           FreeTypeVariableBinding::Disallow,
       ExprTypeCheckListener *listener = nullptr);
 
-  bool typeCheckCompletionSequence(Expr *&expr, DeclContext *DC);
+  /// \brief Return the type of operator function for specified LHS, or a null
+  /// \c Type on error.
+  FunctionType *getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
+                                            Identifier opName,
+                                            DeclRefKind refKind,
+                                            ConcreteDeclRef &referencedDecl);
 
   /// Check the key-path expression.
   ///
@@ -1885,6 +1890,10 @@
   PrecedenceGroupDecl *lookupPrecedenceGroup(DeclContext *dc, Identifier name,
                                              SourceLoc nameLoc);
 
+  /// Given an pre-folded expression, find LHS from the expression if a binary
+  /// operator \c name appended to the expression.
+  Expr *findLHS(DeclContext *DC, Expr *E, Identifier name);
+
   /// \brief Look up the Bool type in the standard library.
   Type lookupBoolType(const DeclContext *dc);
 
diff --git a/test/IDE/complete_from_stdlib.swift b/test/IDE/complete_from_stdlib.swift
index daf976d..b7aad66 100644
--- a/test/IDE/complete_from_stdlib.swift
+++ b/test/IDE/complete_from_stdlib.swift
@@ -282,7 +282,7 @@
 }
 // INFIX_EXT_STRING: Begin completions
 // INFIX_EXT_STRING-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]:  + {#String#}[#String#]
-// INFIX_EXT_STRING-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]:  == {#Bool#}[#Bool#]
 // INFIX_EXT_STRING-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]:  || {#Bool#}[#Bool#]
 // INFIX_EXT_STRING-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]:  && {#Bool#}[#Bool#]
+// INFIX_EXT_STRING-NOT: ==
 // INFIX_EXT_STRING: End completions
diff --git a/test/IDE/complete_operators.swift b/test/IDE/complete_operators.swift
index 2e54a61..5b53fb8 100644
--- a/test/IDE/complete_operators.swift
+++ b/test/IDE/complete_operators.swift
@@ -145,15 +145,20 @@
 
 // ===--- Infix operators
 
+precedencegroup S2PrecedenceGroup {
+  associativity: left
+  lowerThan: ComparisonPrecedence
+  higherThan: AssignmentPrecedence
+}
+precedencegroup S2AssignmentPrecedenceGroup {
+  associativity: none
+  lowerThan: ComparisonPrecedence
+  higherThan: AssignmentPrecedence
+}
+
 struct S2 {}
-infix operator ** {
-  associativity left
-  precedence 123
-}
-infix operator **= {
-  associativity none
-  precedence 123
-}
+infix operator ** : S2PrecedenceGroup
+infix operator **= : S2AssignmentPrecedenceGroup
 func +(x: S2, y: S2) -> S2 { return x }
 func **(x: S2, y: Int) -> S2 { return x }
 func **=(x: inout S2, y: Int) -> Void { return x }
@@ -364,13 +369,13 @@
   x + x == x + x#^EXT_INFIX_2^#
 }
 // S4_EXT_INFIX: Begin completions
-// S4_EXT_INFIX-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]:  != {#Bool#}[#Bool#]
 // S4_EXT_INFIX-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]:  + {#S4#}[#S4#]
-// S4_EXT_INFIX-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]:  == {#Bool#}[#Bool#]
 // S4_EXT_INFIX-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]:  && {#Bool#}[#Bool#]
 // S4_EXT_INFIX-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]:  || {#Bool#}[#Bool#]
 // S4_EXT_INFIX: End completions
 
+// S4_EXT_INFIX-NEG-NOT: !=
+// S4_EXT_INFIX-NEG-NOT: ==
 // S4_EXT_INFIX_NEG-NOT: +++
 // S4_EXT_INFIX_NEG-NOT: &&&
 
@@ -425,4 +430,4 @@
 // INFIX_AUTOCLOSURE_1-DAG: Decl[InfixOperatorFunction]/CurrModule: [' ']&&&& {#Boolish#}[#Boolish#];
 // INFIX_AUTOCLOSURE_1-DAG: Decl[InfixOperatorFunction]/CurrModule: [' ']==== {#Boolish#}[#Boolish#];
 // INFIX_AUTOCLOSURE_1-DAG: Decl[InfixOperatorFunction]/CurrModule: [' ']|||| {#Boolish#}[#Boolish#];
-// INFIX_AUTOCLOSURE_1: End completions
\ No newline at end of file
+// INFIX_AUTOCLOSURE_1: End completions
diff --git a/test/IRGen/lazy_conformances.swift b/test/IRGen/lazy_conformances.swift
new file mode 100644
index 0000000..7f7889d
--- /dev/null
+++ b/test/IRGen/lazy_conformances.swift
@@ -0,0 +1,41 @@
+// RUN: %target-swift-frontend -parse-as-library -O %s -emit-ir | %FileCheck %s
+
+// CHECK: @"$s17lazy_conformances12MyCollectionVyxGSKAASKRzrlMc" = hidden constant {
+// CHECK: @"$s17lazy_conformances12MyCollectionVyxGSTAAMc" = hidden constant {
+
+struct MyCollection<Base : Collection> : Collection {
+  typealias Index = Base.Index
+  typealias Element = Base.Element
+
+  var startIndex: Index {
+    fatalError()
+  }
+
+  var endIndex: Index {
+    fatalError()
+  }
+
+  func index(after i: Index) -> Index {
+    fatalError()
+  }
+
+  func formIndex(after i: inout Index) {
+    fatalError()
+  }
+
+  subscript(position: Index) -> Element {
+    fatalError()
+  }
+}
+
+extension MyCollection : BidirectionalCollection
+  where Base : BidirectionalCollection
+{
+  func index(before i: Index) -> Index {
+    fatalError()
+  }
+
+  func formIndex(before i: inout Index) {
+    fatalError()
+  }
+}
diff --git a/utils/symbolicate-linux-fatal b/utils/symbolicate-linux-fatal
index 8ff5ee5..15c6a81 100755
--- a/utils/symbolicate-linux-fatal
+++ b/utils/symbolicate-linux-fatal
@@ -25,8 +25,10 @@
 from __future__ import print_function
 
 import argparse
+import datetime
 import os
 import subprocess
+import sys
 
 try:
     import lldb
@@ -36,10 +38,17 @@
     if swift_exec is not None:
         site_packages = os.path.join(os.path.dirname(swift_exec),
                                      '../lib/python2.7/site-packages/')
-        import sys
         sys.path.append(site_packages)
         import lldb
 
+lldb_target = None
+known_memmap = {}
+
+
+def print_with_flush(buff):
+    print(buff)
+    sys.stdout.flush()
+
 
 def process_ldd(lddoutput):
     dyn_libs = {}
@@ -53,28 +62,18 @@
     return dyn_libs
 
 
-def create_lldb_target(binary, memmap):
-    lldb_debugger = lldb.SBDebugger.Create()
-    lldb_target = lldb_debugger.CreateTarget(binary)
-    module = lldb_target.GetModuleAtIndex(0)
+def setup_lldb_target(binary, memmap):
+    global lldb_target
+    if not lldb_target:
+        lldb_debugger = lldb.SBDebugger.Create()
+        lldb_target = lldb_debugger.CreateTarget(binary)
+        module = lldb_target.GetModuleAtIndex(0)
     for dynlib_path in memmap:
         module = lldb_target.AddModule(
             dynlib_path, lldb.LLDB_ARCH_DEFAULT, None, None)
         text_section = module.FindSection(".text")
         slide = text_section.GetFileAddress() - text_section.GetFileOffset()
         lldb_target.SetModuleLoadAddress(module, memmap[dynlib_path] - slide)
-    return lldb_target
-
-
-def add_lldb_target_modules(lldb_target, memmap):
-    for dynlib_path in memmap:
-        module = lldb_target.AddModule(
-            dynlib_path, lldb.LLDB_ARCH_DEFAULT, None, None)
-        lldb_target.SetModuleLoadAddress(module, memmap[dynlib_path])
-
-
-lldb_target = None
-known_memmap = {}
 
 
 def check_base_address(dynlib_path, dynlib_baseaddr, memmap):
@@ -116,11 +115,12 @@
            frame_fragment, symbol_fragment, line_fragment)
 
 
-def process_stack(binary, dyn_libs, stack):
+def get_processed_stack(binary, dyn_libs, stack):
     global lldb_target
     global known_memmap
+    processed_stack = []
     if len(stack) == 0:
-        return
+        return processed_stack
     memmap = {}
     full_stack = []
     for line in stack:
@@ -150,20 +150,68 @@
         full_stack.append(
             {"line": line, "framePC": framePC, "dynlib_fname": dynlib_fname})
 
-    if lldb_target is None:
-        lldb_target = create_lldb_target(binary, memmap)
-    else:
-        add_lldb_target_modules(lldb_target, memmap)
-    frame_idx = 0
-    for frame in full_stack:
+    setup_lldb_target(binary, memmap)
+
+    for frame_idx, frame in enumerate(full_stack):
         frame_addr = frame["framePC"]
         dynlib_fname = frame["dynlib_fname"]
         try:
             sym_line = symbolicate_one(frame_addr, frame_idx, dynlib_fname)
-            print(sym_line)
+            processed_stack.append(sym_line)
         except Exception:
-            print(frame["line"].rstrip())
-        frame_idx = frame_idx + 1
+            processed_stack.append(frame["line"].rstrip())
+
+    return processed_stack
+
+
+def is_fatal_error(line):
+    return line.startswith("Fatal error:")
+
+
+def is_stack_trace_header(line):
+    return line.startswith("Current stack trace:")
+
+
+def should_print_previous_line(current_line, previous_line):
+    return is_fatal_error(previous_line) and \
+        not is_stack_trace_header(current_line)
+
+
+def should_print_current_line(current_line, previous_line):
+    return (not is_fatal_error(current_line) and
+            not is_stack_trace_header(current_line)) or \
+           (is_stack_trace_header(current_line) and
+            not is_fatal_error(previous_line))
+
+
+def fatal_error_with_stack_trace_found(current_line, previous_line):
+    return is_stack_trace_header(current_line) and \
+        is_fatal_error(previous_line)
+
+
+def print_stack(fatal_error_header,
+                fatal_error_stack_trace_header,
+                fatal_log_format,
+                processed_stack):
+    if not fatal_error_header:
+        for line in processed_stack:
+            print_with_flush(line)
+    else:
+        # fatal error with a stack trace
+        stack_str = fatal_error_header + fatal_error_stack_trace_header + \
+            '\n'.join(processed_stack)
+        formatted_output = fatal_log_format
+
+        if "%t" in formatted_output:
+            current_time = datetime.datetime.now()
+            time_in_iso_format = \
+                current_time.strftime('%Y-%m-%dT%H:%M:%S,%f%z')
+            formatted_output = \
+                formatted_output.replace("%t", time_in_iso_format)
+        if "%m" in formatted_output:
+            formatted_output = formatted_output.replace("%m", stack_str)
+
+        print_with_flush(formatted_output)
 
 
 def main():
@@ -175,34 +223,69 @@
     parser.add_argument(
         "log", nargs='?', type=argparse.FileType("rU"), default="-",
         help="Log file for symbolication. Defaults to stdin.")
+    parser.add_argument(
+        "--fatal-log-format", default="%m",
+        help="Format for logging fatal errors. Variable %%t will be "
+             "replaced with current time in ISO 8601 format, variable "
+             "%%m will be replaced with the error message with a full "
+             "stack trace.")
     args = parser.parse_args()
 
     binary = args.binary
+    fatal_log_format = args.fatal_log_format
 
     lddoutput = subprocess.check_output(
         ['ldd', binary], stderr=subprocess.STDOUT)
     dyn_libs = process_ldd(lddoutput)
 
     instack = False
+    previous_line = ""
     stackidx = 0
     stack = []
+    fatal_error_header = ""
+    fatal_error_stack_trace_header = ""
 
     while True:
-        line = args.log.readline()
-        if not line:
+        current_line = args.log.readline()
+        if not current_line:
             break
-        if instack and line.startswith(str(stackidx)):
-            stack.append(line)
+        if instack and current_line.startswith(str(stackidx)):
+            stack.append(current_line)
             stackidx = stackidx + 1
         else:
+            processed_stack = get_processed_stack(binary, dyn_libs, stack)
+            print_stack(fatal_error_header,
+                        fatal_error_stack_trace_header,
+                        fatal_log_format,
+                        processed_stack)
+
             instack = False
             stackidx = 0
-            process_stack(binary, dyn_libs, stack)
             stack = []
-            print(line.rstrip())
-        if line.startswith("Current stack trace:"):
-            instack = True
-    process_stack(binary, dyn_libs, stack)
+            fatal_error_header = ""
+            fatal_error_stack_trace_header = ""
+
+            if is_stack_trace_header(current_line):
+                instack = True
+
+            if should_print_previous_line(current_line, previous_line):
+                print_with_flush(previous_line.rstrip())
+
+            if should_print_current_line(current_line, previous_line):
+                print_with_flush(current_line.rstrip())
+
+            if fatal_error_with_stack_trace_found(current_line, previous_line):
+                fatal_error_header = previous_line
+                fatal_error_stack_trace_header = current_line
+
+        previous_line = current_line
+    if is_fatal_error(previous_line):
+        print_with_flush(previous_line.rstrip())
+    processed_stack = get_processed_stack(binary, dyn_libs, stack)
+    print_stack(fatal_error_header,
+                fatal_error_stack_trace_header,
+                fatal_log_format,
+                processed_stack)
 
 
 if __name__ == '__main__':
diff --git a/utils/vim/syntax/swift.vim b/utils/vim/syntax/swift.vim
index e383a82..2654c53 100644
--- a/utils/vim/syntax/swift.vim
+++ b/utils/vim/syntax/swift.vim
@@ -144,7 +144,7 @@
 syn region swiftCaseLabelRegion
       \ matchgroup=swiftKeyword start=/\<case\>/ matchgroup=Delimiter end=/:/ oneline contains=TOP
 syn region swiftDefaultLabelRegion
-      \ matchgroup=swiftKeyword start=/\<default\>/ matchgroup=Delimiter end=/:/
+      \ matchgroup=swiftKeyword start=/\<default\>/ matchgroup=Delimiter end=/:/ oneline
 
 syn region swiftParenthesisRegion matchgroup=NONE start=/(/ end=/)/ contains=TOP
 
diff --git a/validation-test/IDE/slow_fixed/rdar45511835.swift b/validation-test/IDE/slow_fixed/rdar45511835.swift
new file mode 100644
index 0000000..4f9dd01
--- /dev/null
+++ b/validation-test/IDE/slow_fixed/rdar45511835.swift
@@ -0,0 +1,10 @@
+// RUN: %target-swift-ide-test -code-completion -code-completion-token=COMPLETE -source-filename=%s | %FileCheck %s
+
+// This used to take ~6 min to complete.
+
+func testing() {
+  return (["a"] + [1].map { String($0) })
+    .map { $0 + "b" as String }
+    .filter { $0 != "" } #^COMPLETE^#
+}
+// CHECK: Decl[InfixOperatorFunction]/{{.*}}: [' ']+ {#[String]#}[#[String]#]; name=+ [String]