@@ -4166,23 +4166,31 @@ RValue RValueEmitter::visitRebindSelfInConstructorExpr(
41664166  auto  ctorDecl = cast<ConstructorDecl>(selfDecl->getDeclContext ());
41674167  auto  selfIfaceTy = ctorDecl->getDeclContext ()->getSelfInterfaceType ();
41684168  auto  selfTy = ctorDecl->mapTypeIntoContext (selfIfaceTy);
4169-   
4170-   auto  newSelfTy = E->getSubExpr ()->getType ();
4171-   bool  outerIsOptional = false ;
4172-   bool  innerIsOptional = false ;
4173-   auto  objTy = newSelfTy->getOptionalObjectType ();
4174-   if  (objTy) {
4175-     outerIsOptional = true ;
4176-     newSelfTy = objTy;
4177- 
4178-     //  "try? self.init()" can give us two levels of optional if the initializer
4179-     //  we delegate to is failable.
4180-     objTy = newSelfTy->getOptionalObjectType ();
4181-     if  (objTy) {
4182-       innerIsOptional = true ;
4183-       newSelfTy = objTy;
4169+ 
4170+   bool  isChaining; //  Ignored
4171+   auto  *otherCtor = E->getCalledConstructor (isChaining)->getDecl ();
4172+   assert (otherCtor);
4173+ 
4174+   auto  getOptionalityDepth = [](Type ty) {
4175+     unsigned  level = 0 ;
4176+     Type objTy = ty->getOptionalObjectType ();
4177+     while  (objTy) {
4178+       ++level;
4179+       objTy = objTy->getOptionalObjectType ();
41844180    }
4185-   }
4181+ 
4182+     return  level;
4183+   };
4184+ 
4185+   //  The optionality depth of the 'new self' value. This can be '2' if the ctor
4186+   //  we are delegating/chaining to is both throwing and failable, or more if
4187+   //  'self' is optional.
4188+   auto  srcOptionalityDepth = getOptionalityDepth (E->getSubExpr ()->getType ());
4189+ 
4190+   //  The optionality depth of the result type of the enclosing initializer in
4191+   //  this context.
4192+   const  auto  destOptionalityDepth = getOptionalityDepth (
4193+       ctorDecl->mapTypeIntoContext (ctorDecl->getResultInterfaceType ()));
41864194
41874195  //  The subexpression consumes the current 'self' binding.
41884196  assert (SGF.SelfInitDelegationState  == SILGenFunction::NormalSelf
@@ -4199,13 +4207,25 @@ RValue RValueEmitter::visitRebindSelfInConstructorExpr(
41994207    SGF.emitAddressOfLocalVarDecl (E, selfDecl, selfTy->getCanonicalType (),
42004208                                  SGFAccessKind::Write).getLValueAddress ();
42014209
4202-   //  Handle a nested optional case (see above).
4203-   if  (innerIsOptional)
4210+   //  Flatten a nested optional if 'new self' is a deeper optional than we
4211+   //  can return.
4212+   if  (srcOptionalityDepth > destOptionalityDepth) {
4213+     assert (destOptionalityDepth > 0 );
4214+     assert (otherCtor->isFailable () && otherCtor->hasThrows ());
4215+ 
4216+     --srcOptionalityDepth;
42044217    newSelf = flattenOptional (SGF, E, newSelf);
42054218
4206-   //  If both the delegated-to initializer and our enclosing initializer can
4207-   //  fail, deal with the failure.
4208-   if  (outerIsOptional && ctorDecl->isFailable ()) {
4219+     assert (srcOptionalityDepth == destOptionalityDepth &&
4220+            " Flattening a single level was not enough?"  );
4221+   }
4222+ 
4223+   //  If the enclosing ctor is failable and the optionality depths match, switch
4224+   //  on 'new self' to either return 'nil' or continue with the projected value.
4225+   if  (srcOptionalityDepth == destOptionalityDepth && ctorDecl->isFailable ()) {
4226+     assert (destOptionalityDepth > 0 );
4227+     assert (otherCtor->isFailable () || otherCtor->hasThrows ());
4228+ 
42094229    SILBasicBlock *someBB = SGF.createBasicBlock ();
42104230
42114231    auto  hasValue = SGF.emitDoesOptionalHaveValue (E, newSelf.getValue ());
@@ -4224,7 +4244,7 @@ RValue RValueEmitter::visitRebindSelfInConstructorExpr(
42244244                                    SGF.getTypeLowering (newSelf.getType ()),
42254245                                                    SGFContext ());
42264246  }
4227-    
4247+ 
42284248  //  If we called a constructor that requires a downcast, perform the downcast.
42294249  auto  destTy = SGF.getLoweredType (selfTy);
42304250  if  (newSelf.getType () != destTy) {
0 commit comments