From ed24d325b760b9eb7392168e9b88120a8c806e0b Mon Sep 17 00:00:00 2001 From: Adam Cmiel Date: Thu, 27 Mar 2025 00:31:44 -0400 Subject: [PATCH] [Sema] Dig out other constructor if call is wrapped in a Dot-Call Guessing this bug /feature is introduced in CSApply ExprRewriter::buildMemberRef but didn't dig deep enough to find there. If a derived class' designated initializer initializes all stored let properties before calling super.init(), we don't properly type-check the chained init call. This does not happen if the stored properties are var or default initialized. We can however dig the OtherConstructorDeclRefExpr out of the semanticFn of the DotSyntaxCallExpr and proceed as normal. --- lib/Sema/TypeCheckStmt.cpp | 10 +++++-- test/decl/func/complete_object_init.swift | 34 ++++++++++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index eb3495302f68e..7ad3b65597a4f 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -2163,11 +2163,15 @@ static Expr* constructCallToSuperInit(ConstructorDecl *ctor, /// \returns true if an error occurred. static bool checkSuperInit(ConstructorDecl *fromCtor, ApplyExpr *apply, bool implicitlyGenerated) { + auto Callee = apply->getSemanticFn(); + if (auto dotCall = dyn_cast(Callee)) + Callee = dotCall->getSemanticFn(); + // Make sure we are referring to a designated initializer. - auto otherCtorRef = dyn_cast( - apply->getSemanticFn()); - if (!otherCtorRef) + auto otherCtorRef = dyn_cast(Callee); + if (!otherCtorRef) { return false; + } auto ctor = otherCtorRef->getDecl(); if (!ctor->isDesignatedInit()) { diff --git a/test/decl/func/complete_object_init.swift b/test/decl/func/complete_object_init.swift index 7028f89416b36..6059dbc55f45d 100644 --- a/test/decl/func/complete_object_init.swift +++ b/test/decl/func/complete_object_init.swift @@ -4,7 +4,7 @@ // Declaration of complete object initializers and basic semantic checking // --------------------------------------------------------------------------- class A { - convenience init(int i: Int) { // expected-note{{convenience initializer is declared here}} + convenience init(int i: Int) { // expected-note 5 {{convenience initializer is declared here}} self.init(double: Double(i)) } @@ -39,6 +39,38 @@ class DerivesA : A { } } +// Fixing https://github.com/swiftlang/swift/issues/80311 +class DerivesAWithLet : A { + let str: String + init(int i: Int) { + str = "foo" + super.init(int: i) // expected-error{{must call a designated initializer of the superclass 'A'}} + } +} + +class DerivesAWithVar : A { + var str: String + init(int i: Int) { + str = "foo" + super.init(int: i) // expected-error{{must call a designated initializer of the superclass 'A'}} + } +} + +class DerivesAWithDefaultLet : A { + let str: String = "foo" + init(int i: Int) { + super.init(int: i) // expected-error{{must call a designated initializer of the superclass 'A'}} + } +} + +class DerivesAWithDefaultVar : A { + var str: String = "foo" + init(int i: Int) { + super.init(int: i) // expected-error{{must call a designated initializer of the superclass 'A'}} + } +} + + struct S { convenience init(int i: Int) { // expected-error{{initializers in structs are not marked with 'convenience'}} self.init(double: Double(i))