Merge pull request #13897 from slavapestov/fixed-layout-property-initializer-restriction

Fixed layout property initializer restriction
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 8b9a07c..ae8b248 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -4320,6 +4320,11 @@
 
   if (withTypes && PD->hasInterfaceType())
     setInterfaceType(PD->getInterfaceType()->getInOutObjectType());
+
+  // FIXME: We should clone the entire attribute list.
+  if (PD->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
+    getAttrs().add(new (PD->getASTContext())
+                       ImplicitlyUnwrappedOptionalAttr(/* implicit= */ true));
 }
 
 
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index 00cc13e..747d347 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -5738,10 +5738,43 @@
       return true;
 
     if (!lhsType->isEqual(rhsType)) {
-      diagnose(callExpr->getLoc(), diag::cannot_apply_binop_to_args,
-               overloadName, lhsType, rhsType)
-      .highlight(lhsExpr->getSourceRange())
+      auto diag = diagnose(callExpr->getLoc(), diag::cannot_apply_binop_to_args,
+                           overloadName, lhsType, rhsType);
+      diag.highlight(lhsExpr->getSourceRange())
       .highlight(rhsExpr->getSourceRange());
+
+      auto tryFixIts = [&]() -> bool {
+        if (calleeInfo.size() != 1)
+          return false;
+
+        auto candidate = calleeInfo[0];
+        auto *fnType = candidate.getUncurriedFunctionType();
+        if (!fnType)
+          return false;
+
+        auto params = fnType->getParams();
+        if (params.size() != 2)
+          return false;
+
+        auto lhsCandidate = params[0].getType();
+        auto rhsCandidate = params[1].getType();
+        auto lhsIsCandidate = lhsType->isEqual(lhsCandidate);
+        auto rhsIsCandidate = rhsType->isEqual(rhsCandidate);
+
+        if (!lhsIsCandidate && !rhsIsCandidate)
+          return false;
+
+        if (!lhsIsCandidate)
+          return tryIntegerCastFixIts(diag, CS, lhsType, lhsCandidate, lhsExpr);
+
+        if (!rhsIsCandidate)
+          return tryIntegerCastFixIts(diag, CS, rhsType, rhsCandidate, rhsExpr);
+
+        return false;
+      };
+
+      tryFixIts();
+
     } else {
       diagnose(callExpr->getLoc(), diag::cannot_apply_binop_to_same_args,
                overloadName, lhsType)
diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift
index a431c54..7080436 100644
--- a/test/Constraints/diagnostics.swift
+++ b/test/Constraints/diagnostics.swift
@@ -930,6 +930,76 @@
 let _ = ((r29850459_flag || r29850459()) ? r29850459_a : r29850459_b) + 42.0 // expected-error {{binary operator '+' cannot be applied to operands of type 'Int' and 'Double'}}
 // expected-note@-1 {{overloads for '+' exist with these partially matching parameter lists: (Double, Double), (Int, Int), (Int, UnsafeMutablePointer<Pointee>), (Int, UnsafePointer<Pointee>)}}
 
+// SR-6272: Tailored diagnostics with fixits for numerical conversions
+
+func SR_6272_a() {
+  enum Foo: Int {
+    case bar
+  }
+
+  // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Int' and 'Float'}} {{35-41=}} {{42-43=}}
+  // expected-note@+1 {{expected an argument list of type '(Int, Int)'}}
+  let _: Int = Foo.bar.rawValue * Float(0)
+
+  // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Int' and 'Float'}} {{18-18=Float(}} {{34-34=)}}
+  // expected-note@+1 {{expected an argument list of type '(Float, Float)'}}
+  let _: Float = Foo.bar.rawValue * Float(0)
+
+  // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Int' and 'Float'}} {{none}}
+  // expected-note@+1 {{overloads for '*' exist with these partially matching parameter lists: (Float, Float), (Int, Int)}}
+  Foo.bar.rawValue * Float(0)
+}
+
+func SR_6272_b() {
+  let lhs = Float(3)
+  let rhs = Int(0)
+
+  // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Float' and 'Int'}} {{24-24=Float(}} {{27-27=)}}
+  // expected-note@+1 {{expected an argument list of type '(Float, Float)'}}
+  let _: Float = lhs * rhs
+
+  // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Float' and 'Int'}} {{16-16=Int(}} {{19-19=)}}
+  // expected-note@+1 {{expected an argument list of type '(Int, Int)'}}
+  let _: Int = lhs * rhs
+
+  // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Float' and 'Int'}} {{none}}
+  // expected-note@+1 {{overloads for '*' exist with these partially matching parameter lists: (Float, Float), (Int, Int)}}
+  lhs * rhs
+}
+
+func SR_6272_c() {
+  // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Int' and 'String'}} {{none}}
+  // expected-note@+1 {{expected an argument list of type '(Int, Int)'}}
+  Int(3) * "0"
+
+  struct S {}
+  // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Int' and 'S'}} {{none}}
+  // expected-note@+1 {{expected an argument list of type '(Int, Int)'}}
+  Int(10) * S()
+}
+
+struct SR_6272_D: ExpressibleByIntegerLiteral {
+  typealias IntegerLiteralType = Int
+  init(integerLiteral: Int) {}
+  static func +(lhs: SR_6272_D, rhs: Int) -> Float { return 42.0 }
+}
+
+func SR_6272_d() {
+  let x: Float = 1.0
+
+  // expected-error@+2 {{binary operator '+' cannot be applied to operands of type 'SR_6272_D' and 'Float'}} {{none}}
+  // expected-note@+1 {{overloads for '+' exist with these partially matching parameter lists: (SR_6272_D, Int), (Float, Float)}}
+  let _: Float = SR_6272_D(integerLiteral: 42) + x
+
+  // expected-error@+2 {{binary operator '+' cannot be applied to operands of type 'SR_6272_D' and 'Double'}} {{none}}
+  // expected-note@+1 {{overloads for '+' exist with these partially matching parameter lists: (SR_6272_D, Int), (Double, Double)}}
+  let _: Float = SR_6272_D(integerLiteral: 42) + 42.0
+
+  // expected-error@+2 {{binary operator '+' cannot be applied to operands of type 'SR_6272_D' and 'Float'}} {{none}}
+  // expected-note@+1 {{overloads for '+' exist with these partially matching parameter lists: (SR_6272_D, Int), (Float, Float)}}
+  let _: Float = SR_6272_D(integerLiteral: 42) + x + 1.0
+}
+
 // Ambiguous overload inside a trailing closure
 
 func ambiguousCall() -> Int {} // expected-note {{found this candidate}}