Skip to content

Commit 57ed4fc

Browse files
authored
Merge pull request #16901 from slavapestov/missing-diagnostic-for-required-init
Fix crash-on-invalid when calling non-required init on a metatype
2 parents a7d887e + 69701b1 commit 57ed4fc

File tree

3 files changed

+53
-22
lines changed

3 files changed

+53
-22
lines changed

lib/AST/Expr.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -639,15 +639,24 @@ bool Expr::isTypeReference(
639639

640640
bool Expr::isStaticallyDerivedMetatype(
641641
llvm::function_ref<Type(const Expr *)> getType) const {
642-
// The type must first be a type reference.
642+
// The expression must first be a type reference.
643643
if (!isTypeReference(getType))
644644
return false;
645645

646+
auto type = getType(this)
647+
->castTo<AnyMetatypeType>()
648+
->getInstanceType();
649+
646650
// Archetypes are never statically derived.
647-
return !getType(this)
648-
->getAs<AnyMetatypeType>()
649-
->getInstanceType()
650-
->is<ArchetypeType>();
651+
if (type->is<ArchetypeType>())
652+
return false;
653+
654+
// Dynamic Self is never statically derived.
655+
if (type->is<DynamicSelfType>())
656+
return false;
657+
658+
// Everything else is statically derived.
659+
return true;
651660
}
652661

653662
bool Expr::isSuperExpr() const {

lib/Sema/CSApply.cpp

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -359,16 +359,6 @@ diagnoseInvalidDynamicConstructorReferences(ConstraintSystem &cs,
359359
return cs.getType(expr);
360360
});
361361

362-
// 'super.' is always OK
363-
if (isa<SuperRefExpr>(base))
364-
return true;
365-
366-
// 'self.' reference with concrete type is OK
367-
if (isa<DeclRefExpr>(base) &&
368-
cast<DeclRefExpr>(base)->getDecl()->getBaseName() == tc.Context.Id_self &&
369-
!baseTy->is<ArchetypeType>())
370-
return true;
371-
372362
// FIXME: The "hasClangNode" check here is a complete hack.
373363
if (isNonFinalClass(instanceTy) &&
374364
!isStaticallyDerived &&
@@ -2697,12 +2687,6 @@ namespace {
26972687

26982688
auto *ctor = cast<ConstructorDecl>(choice.getDecl());
26992689

2700-
// If the member is a constructor, verify that it can be legally
2701-
// referenced from this base.
2702-
if (!diagnoseInvalidDynamicConstructorReferences(cs, base, nameLoc,
2703-
ctor, SuppressDiagnostics))
2704-
return nullptr;
2705-
27062690
// If the subexpression is a metatype, build a direct reference to the
27072691
// constructor.
27082692
if (cs.getType(base)->is<AnyMetatypeType>()) {
@@ -2725,6 +2709,17 @@ namespace {
27252709
// We have a reference to 'self'.
27262710
diagnoseBadInitRef = false;
27272711

2712+
// Special case -- in a protocol extension initializer with a class
2713+
// constrainted Self type, 'self' has archetype type, and only
2714+
// required initializers can be called.
2715+
if (cs.getType(dre)->getRValueType()->is<ArchetypeType>()) {
2716+
if (!diagnoseInvalidDynamicConstructorReferences(cs, base,
2717+
nameLoc,
2718+
ctor,
2719+
SuppressDiagnostics))
2720+
return nullptr;
2721+
}
2722+
27282723
// Make sure the reference to 'self' occurs within an initializer.
27292724
if (!dyn_cast_or_null<ConstructorDecl>(
27302725
cs.DC->getInnermostMethodContext())) {

test/expr/postfix/call/construction.swift

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,40 @@ enum E {
2121
}
2222

2323
class C {
24-
init(i: Int) { } // expected-note{{selected non-required initializer 'init(i:)'}}
24+
init(i: Int) { } // expected-note 4{{selected non-required initializer 'init(i:)'}}
2525

2626
required init(d: Double) { }
2727

2828
class Inner {
2929
init(i: Int) { }
3030
}
31+
32+
static func makeCBad() -> C {
33+
return self.init(i: 0)
34+
// expected-error@-1 {{constructing an object of class type 'C' with a metatype value must use a 'required' initializer}}
35+
}
36+
37+
static func makeCGood() -> C {
38+
return self.init(d: 0)
39+
}
40+
41+
static func makeSelfBad() -> Self {
42+
return self.init(i: 0)
43+
// expected-error@-1 {{constructing an object of class type 'Self' with a metatype value must use a 'required' initializer}}
44+
}
45+
46+
static func makeSelfGood() -> Self {
47+
return self.init(d: 0)
48+
}
49+
50+
static func makeSelfImplicitBaseBad() -> Self {
51+
return .init(i: 0)
52+
// expected-error@-1 {{constructing an object of class type 'Self' with a metatype value must use a 'required' initializer}}
53+
}
54+
55+
static func makeSelfImplicitBaseGood() -> Self {
56+
return .init(d: 0)
57+
}
3158
}
3259

3360
final class D {

0 commit comments

Comments
 (0)