Skip to content

Commit 71afed8

Browse files
committed
Sema: Clean up 'polymorphic use of non-required initializer' diagnostic
1 parent b217d36 commit 71afed8

File tree

2 files changed

+72
-73
lines changed

2 files changed

+72
-73
lines changed

lib/Sema/CSApply.cpp

Lines changed: 72 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,75 @@ static bool buildObjCKeyPathString(KeyPathExpr *E,
321321
return true;
322322
}
323323

324+
/// Determine whether the given type refers to a non-final class (or
325+
/// dynamic self of one).
326+
static bool isNonFinalClass(Type type) {
327+
if (auto dynamicSelf = type->getAs<DynamicSelfType>())
328+
type = dynamicSelf->getSelfType();
329+
330+
if (auto classDecl = type->getClassOrBoundGenericClass())
331+
return !classDecl->isFinal();
332+
333+
if (auto archetype = type->getAs<ArchetypeType>())
334+
if (auto super = archetype->getSuperclass())
335+
return isNonFinalClass(super);
336+
337+
return false;
338+
}
339+
340+
// Non-required constructors may not be not inherited. Therefore when
341+
// constructing a class object, either the metatype must be statically
342+
// derived (rather than an arbitrary value of metatype type) or the referenced
343+
// constructor must be required.
344+
static bool
345+
diagnoseInvalidDynamicConstructorReferences(ConstraintSystem &cs,
346+
Expr *base,
347+
DeclNameLoc memberRefLoc,
348+
ConstructorDecl *ctorDecl,
349+
bool SuppressDiagnostics) {
350+
auto &tc = cs.getTypeChecker();
351+
auto baseTy = cs.getType(base)->getRValueType();
352+
auto instanceTy = baseTy->getRValueInstanceType();
353+
354+
bool isStaticallyDerived =
355+
base->isStaticallyDerivedMetatype(
356+
[&](const Expr *expr) -> Type {
357+
return cs.getType(expr);
358+
});
359+
360+
// FIXME: The "hasClangNode" check here is a complete hack.
361+
if (isNonFinalClass(instanceTy) &&
362+
!isStaticallyDerived &&
363+
!ctorDecl->hasClangNode() &&
364+
!(ctorDecl->isRequired() ||
365+
ctorDecl->getDeclContext()->getAsProtocolOrProtocolExtensionContext())) {
366+
if (SuppressDiagnostics)
367+
return false;
368+
369+
tc.diagnose(memberRefLoc, diag::dynamic_construct_class, instanceTy)
370+
.highlight(base->getSourceRange());
371+
auto ctor = cast<ConstructorDecl>(ctorDecl);
372+
tc.diagnose(ctorDecl, diag::note_nonrequired_initializer,
373+
ctor->isImplicit(), ctor->getFullName());
374+
// Constructors cannot be called on a protocol metatype, because there is no
375+
// metatype to witness it.
376+
} else if (isa<ConstructorDecl>(ctorDecl) &&
377+
baseTy->is<MetatypeType>() &&
378+
instanceTy->isExistentialType()) {
379+
if (SuppressDiagnostics)
380+
return false;
381+
382+
if (isStaticallyDerived) {
383+
tc.diagnose(memberRefLoc, diag::construct_protocol_by_name, instanceTy)
384+
.highlight(base->getSourceRange());
385+
} else {
386+
tc.diagnose(memberRefLoc, diag::construct_protocol_value, baseTy)
387+
.highlight(base->getSourceRange());
388+
}
389+
}
390+
return true;
391+
}
392+
324393
namespace {
325394

326395
/// \brief Rewrites an expression by applying the solution of a constraint
@@ -825,12 +894,12 @@ namespace {
825894
if (auto baseMeta = baseTy->getAs<AnyMetatypeType>()) {
826895
baseIsInstance = false;
827896
baseTy = baseMeta->getInstanceType();
897+
828898
// If the member is a constructor, verify that it can be legally
829899
// referenced from this base.
830900
if (auto ctor = dyn_cast<ConstructorDecl>(member)) {
831-
cs.setExprTypes(base);
832-
if (!tc.diagnoseInvalidDynamicConstructorReferences(base, memberLoc,
833-
baseMeta, ctor, SuppressDiagnostics))
901+
if (!diagnoseInvalidDynamicConstructorReferences(cs, base, memberLoc,
902+
ctor, SuppressDiagnostics))
834903
return nullptr;
835904
}
836905
}
@@ -6805,67 +6874,6 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
68056874
return literal;
68066875
}
68076876

6808-
/// Determine whether the given type refers to a non-final class (or
6809-
/// dynamic self of one).
6810-
static bool isNonFinalClass(Type type) {
6811-
if (auto dynamicSelf = type->getAs<DynamicSelfType>())
6812-
type = dynamicSelf->getSelfType();
6813-
6814-
if (auto classDecl = type->getClassOrBoundGenericClass())
6815-
return !classDecl->isFinal();
6816-
6817-
if (auto archetype = type->getAs<ArchetypeType>())
6818-
if (auto super = archetype->getSuperclass())
6819-
return isNonFinalClass(super);
6820-
6821-
return false;
6822-
}
6823-
6824-
// Non-required constructors may not be not inherited. Therefore when
6825-
// constructing a class object, either the metatype must be statically
6826-
// derived (rather than an arbitrary value of metatype type) or the referenced
6827-
// constructor must be required.
6828-
bool
6829-
TypeChecker::diagnoseInvalidDynamicConstructorReferences(Expr *base,
6830-
DeclNameLoc memberRefLoc,
6831-
AnyMetatypeType *metaTy,
6832-
ConstructorDecl *ctorDecl,
6833-
bool SuppressDiagnostics) {
6834-
auto ty = metaTy->getInstanceType();
6835-
6836-
// FIXME: The "hasClangNode" check here is a complete hack.
6837-
if (isNonFinalClass(ty) &&
6838-
!base->isStaticallyDerivedMetatype() &&
6839-
!ctorDecl->hasClangNode() &&
6840-
!(ctorDecl->isRequired() ||
6841-
ctorDecl->getDeclContext()->getAsProtocolOrProtocolExtensionContext())) {
6842-
if (SuppressDiagnostics)
6843-
return false;
6844-
6845-
diagnose(memberRefLoc, diag::dynamic_construct_class, ty)
6846-
.highlight(base->getSourceRange());
6847-
auto ctor = cast<ConstructorDecl>(ctorDecl);
6848-
diagnose(ctorDecl, diag::note_nonrequired_initializer,
6849-
ctor->isImplicit(), ctor->getFullName());
6850-
// Constructors cannot be called on a protocol metatype, because there is no
6851-
// metatype to witness it.
6852-
} else if (isa<ConstructorDecl>(ctorDecl) &&
6853-
isa<MetatypeType>(metaTy) &&
6854-
ty->isExistentialType()) {
6855-
if (SuppressDiagnostics)
6856-
return false;
6857-
6858-
if (base->isStaticallyDerivedMetatype()) {
6859-
diagnose(memberRefLoc, diag::construct_protocol_by_name, ty)
6860-
.highlight(base->getSourceRange());
6861-
} else {
6862-
diagnose(memberRefLoc, diag::construct_protocol_value, metaTy)
6863-
.highlight(base->getSourceRange());
6864-
}
6865-
}
6866-
return true;
6867-
}
6868-
68696877
Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
68706878
ConstraintLocatorBuilder locator) {
68716879
TypeChecker &tc = cs.getTypeChecker();

lib/Sema/TypeChecker.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2468,15 +2468,6 @@ class TypeChecker final : public LazyResolver {
24682468
/// Diagnose assigning variable to itself.
24692469
bool diagnoseSelfAssignment(const Expr *E);
24702470

2471-
/// When referencing a class initializer, check that the base expression is
2472-
/// either a static metatype or that the initializer is 'required'.
2473-
bool
2474-
diagnoseInvalidDynamicConstructorReferences(Expr *base,
2475-
DeclNameLoc memberRefLoc,
2476-
AnyMetatypeType *metaTy,
2477-
ConstructorDecl *ctorDecl,
2478-
bool SuppressDiagnostics);
2479-
24802471
/// Builds a string representing a "default" generic argument list for
24812472
/// \p typeDecl. In general, this means taking the bound of each generic
24822473
/// parameter. The \p getPreferredType callback can be used to provide a

0 commit comments

Comments
 (0)