Skip to content

Commit dcc27ea

Browse files
committed
Sema: Fix failure to emit diagnostic with some invalid member type references
There were two problems here: - isUnsupportedMemberTypeReference() checked if the immediate parent type was an unbound generic type, but did not check for the parent of the parent, etc. - The caller of isUnsupportedMemberTypeReference() had to re-check the various invalid conditions to determine what diagnostic to emit, and if none of those conditions matched it would just return an ErrorType without emitting a diagnostic. Fix both of these by having isUnsupportedMemberTypeReference() return an enum indicating what went wrong, and handle more cases. Fixes <rdar://problem/67292528>.
1 parent 1e09ad0 commit dcc27ea

File tree

8 files changed

+90
-47
lines changed

8 files changed

+90
-47
lines changed

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1853,9 +1853,11 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
18531853
if (auto rawTy = ED->getRawType()) {
18541854
// The raw type must be one of the blessed literal convertible types.
18551855
if (!computeAutomaticEnumValueKind(ED)) {
1856-
DE.diagnose(ED->getInherited().front().getSourceRange().Start,
1857-
diag::raw_type_not_literal_convertible, rawTy);
1858-
ED->getInherited().front().setType(ErrorType::get(getASTContext()));
1856+
if (!rawTy->is<ErrorType>()) {
1857+
DE.diagnose(ED->getInherited().front().getSourceRange().Start,
1858+
diag::raw_type_not_literal_convertible, rawTy);
1859+
ED->getInherited().front().setType(ErrorType::get(getASTContext()));
1860+
}
18591861
}
18601862

18611863
// We need at least one case to have a raw value.

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -338,18 +338,16 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc,
338338
return result;
339339
}
340340

341-
bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) {
341+
TypeChecker::UnsupportedMemberTypeAccessKind
342+
TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) {
342343
// We don't allow lookups of a non-generic typealias of an unbound
343344
// generic type, because we have no way to model such a type in the
344345
// AST.
345346
//
346347
// For generic typealiases, the typealias itself has an unbound
347348
// generic form whose parent type can be another unbound generic
348349
// type.
349-
//
350-
// FIXME: Could lift this restriction once we have sugared
351-
// "member types".
352-
if (type->is<UnboundGenericType>()) {
350+
if (type->hasUnboundGenericType()) {
353351
// Generic typealiases can be accessed with an unbound generic
354352
// base, since we represent the member type as an unbound generic
355353
// type.
@@ -359,12 +357,12 @@ bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) {
359357
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
360358
if (!aliasDecl->isGeneric() &&
361359
aliasDecl->getUnderlyingType()->hasTypeParameter()) {
362-
return true;
360+
return UnsupportedMemberTypeAccessKind::TypeAliasOfUnboundGeneric;
363361
}
364362
}
365363

366364
if (isa<AssociatedTypeDecl>(typeDecl))
367-
return true;
365+
return UnsupportedMemberTypeAccessKind::AssociatedTypeOfUnboundGeneric;
368366
}
369367

370368
if (type->isExistentialType() &&
@@ -374,15 +372,13 @@ bool TypeChecker::isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl) {
374372
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
375373
if (aliasDecl->getUnderlyingType()->getCanonicalType()
376374
->hasTypeParameter())
377-
return true;
378-
} else {
379-
// Don't allow lookups of other nested types of an existential type,
380-
// because there is no way to represent such types.
381-
return true;
375+
return UnsupportedMemberTypeAccessKind::TypeAliasOfExistential;
376+
} else if (isa<AssociatedTypeDecl>(typeDecl)) {
377+
return UnsupportedMemberTypeAccessKind::AssociatedTypeOfExistential;
382378
}
383379
}
384380

385-
return false;
381+
return UnsupportedMemberTypeAccessKind::None;
386382
}
387383

388384
LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
@@ -419,7 +415,8 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
419415
continue;
420416
}
421417

422-
if (isUnsupportedMemberTypeAccess(type, typeDecl)) {
418+
if (isUnsupportedMemberTypeAccess(type, typeDecl)
419+
!= TypeChecker::UnsupportedMemberTypeAccessKind::None) {
423420
auto memberType = typeDecl->getDeclaredInterfaceType();
424421

425422
// Add the type to the result set, so that we can diagnose the

lib/Sema/TypeCheckType.cpp

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -945,21 +945,32 @@ Type TypeChecker::applyUnboundGenericArguments(GenericTypeDecl *decl,
945945

946946
/// Diagnose a use of an unbound generic type.
947947
static void diagnoseUnboundGenericType(Type ty, SourceLoc loc) {
948-
auto unbound = ty->castTo<UnboundGenericType>();
949-
{
950-
auto &ctx = ty->getASTContext();
951-
InFlightDiagnostic diag = ctx.Diags.diagnose(loc,
952-
diag::generic_type_requires_arguments, ty);
953-
if (auto *genericD = unbound->getDecl()) {
948+
auto &ctx = ty->getASTContext();
949+
if (auto unbound = ty->getAs<UnboundGenericType>()) {
950+
auto *decl = unbound->getDecl();
951+
{
952+
InFlightDiagnostic diag = ctx.Diags.diagnose(loc,
953+
diag::generic_type_requires_arguments, ty);
954954
SmallString<64> genericArgsToAdd;
955955
if (TypeChecker::getDefaultGenericArgumentsString(genericArgsToAdd,
956-
genericD))
956+
decl))
957957
diag.fixItInsertAfter(loc, genericArgsToAdd);
958958
}
959+
960+
decl->diagnose(diag::kind_declname_declared_here,
961+
DescriptiveDeclKind::GenericType,
962+
decl->getName());
963+
} else {
964+
ty.findIf([&](Type t) -> bool {
965+
if (auto unbound = t->getAs<UnboundGenericType>()) {
966+
ctx.Diags.diagnose(loc,
967+
diag::generic_type_requires_arguments, t);
968+
return true;
969+
}
970+
971+
return false;
972+
});
959973
}
960-
unbound->getDecl()->diagnose(diag::kind_declname_declared_here,
961-
DescriptiveDeclKind::GenericType,
962-
unbound->getDecl()->getName());
963974
}
964975

965976
// Produce a diagnostic if the type we referenced was an
@@ -1417,22 +1428,29 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution,
14171428

14181429
auto maybeDiagnoseBadMemberType = [&](TypeDecl *member, Type memberType,
14191430
AssociatedTypeDecl *inferredAssocType) {
1420-
// Diagnose invalid cases.
1421-
if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)) {
1422-
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
1423-
if (parentTy->is<UnboundGenericType>())
1424-
diagnoseUnboundGenericType(parentTy, parentRange.End);
1425-
else if (parentTy->isExistentialType() &&
1426-
isa<AssociatedTypeDecl>(member)) {
1427-
diags.diagnose(comp->getNameLoc(), diag::assoc_type_outside_of_protocol,
1428-
comp->getNameRef());
1429-
} else if (parentTy->isExistentialType() &&
1430-
isa<TypeAliasDecl>(member)) {
1431-
diags.diagnose(comp->getNameLoc(), diag::typealias_outside_of_protocol,
1432-
comp->getNameRef());
1433-
}
1434-
}
1431+
if (options.contains(TypeResolutionFlags::SilenceErrors)) {
1432+
if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)
1433+
!= TypeChecker::UnsupportedMemberTypeAccessKind::None)
1434+
return ErrorType::get(ctx);
1435+
}
1436+
1437+
switch (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)) {
1438+
case TypeChecker::UnsupportedMemberTypeAccessKind::None:
1439+
break;
1440+
1441+
case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfUnboundGeneric:
1442+
case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfUnboundGeneric:
1443+
diagnoseUnboundGenericType(parentTy, parentRange.End);
1444+
return ErrorType::get(ctx);
1445+
1446+
case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfExistential:
1447+
diags.diagnose(comp->getNameLoc(), diag::typealias_outside_of_protocol,
1448+
comp->getNameRef());
1449+
return ErrorType::get(ctx);
14351450

1451+
case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfExistential:
1452+
diags.diagnose(comp->getNameLoc(), diag::assoc_type_outside_of_protocol,
1453+
comp->getNameRef());
14361454
return ErrorType::get(ctx);
14371455
}
14381456

lib/Sema/TypeChecker.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -927,9 +927,18 @@ PrecedenceGroupDecl *lookupPrecedenceGroupForInfixOperator(DeclContext *dc,
927927
PrecedenceGroupLookupResult
928928
lookupPrecedenceGroup(DeclContext *dc, Identifier name, SourceLoc nameLoc);
929929

930+
enum class UnsupportedMemberTypeAccessKind : uint8_t {
931+
None,
932+
TypeAliasOfUnboundGeneric,
933+
TypeAliasOfExistential,
934+
AssociatedTypeOfUnboundGeneric,
935+
AssociatedTypeOfExistential
936+
};
937+
930938
/// Check whether the given declaration can be written as a
931939
/// member of the given base type.
932-
bool isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl);
940+
UnsupportedMemberTypeAccessKind
941+
isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl);
933942

934943
/// @}
935944

test/Generics/unbound.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,20 @@ struct X1<T> {
7474
func bar<U>() where T: X2<U> {}
7575
}
7676
class X2<T> {}
77+
78+
// <rdar://problem/67292528> missing check for unbound parent type
79+
struct Outer<K, V> {
80+
struct Inner {}
81+
82+
struct Middle {
83+
typealias Inner = Outer<K, V>.Middle
84+
}
85+
}
86+
87+
func makeInner() -> Outer<String, String>.Middle.Inner {
88+
return .init()
89+
}
90+
91+
var innerProperty: Outer.Middle.Inner = makeInner()
92+
// expected-error@-1 {{reference to generic type 'Outer' requires arguments in <...>}}
93+

test/IDE/print_ast_tc_decls_errors.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ class ClassWithInheritance9 : FooClass, BarClass, FooProtocol, BarProtocol, FooN
109109
//===--- Inheritance list in enums.
110110
//===---
111111

112-
enum EnumWithInheritance1 : FooNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{raw type}} expected-error {{an enum with no cases}}
112+
enum EnumWithInheritance1 : FooNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{an enum with no cases}}
113113
// NO-TYREPR: {{^}}enum EnumWithInheritance1 : <<error type>> {{{$}}
114114
// TYREPR: {{^}}enum EnumWithInheritance1 : FooNonExistentProtocol {{{$}}
115115

116-
enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{cannot find type 'BarNonExistentProtocol' in scope}} expected-error {{raw type}} expected-error {{an enum with no cases}}
116+
enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {} // expected-error {{cannot find type 'FooNonExistentProtocol' in scope}} expected-error {{cannot find type 'BarNonExistentProtocol' in scope}} expected-error {{an enum with no cases}}
117117
// NO-TYREPR: {{^}}enum EnumWithInheritance2 : <<error type>>, <<error type>> {{{$}}
118118
// TYREPR: {{^}}enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {{{$}}
119119

test/decl/nested/protocol.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ protocol Racoon {
5151
}
5252

5353
enum SillyRawEnum : SillyProtocol.InnerClass {} // expected-error {{an enum with no cases cannot declare a raw type}}
54-
// expected-error@-1 {{raw type}}
54+
// expected-error@-1 {{reference to generic type 'SillyProtocol.InnerClass' requires arguments in <...>}}
5555

5656
protocol SillyProtocol {
5757
class InnerClass<T> {} // expected-error {{type 'InnerClass' cannot be nested in protocol 'SillyProtocol'}}
58+
// expected-note@-1 {{generic type 'InnerClass' declared here}}
5859
}
5960

6061
// N.B. Redeclaration checks don't see this case because `protocol A` is invalid.

test/decl/overload.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ enum mixed_redecl3 {} // expected-error {{invalid redeclaration}}
7979
// expected-note @-1 2{{found this candidate}}
8080
enum mixed_redecl3a : mixed_redecl3 {} // expected-error {{'mixed_redecl3' is ambiguous for type lookup in this context}}
8181
// expected-error@-1 {{an enum with no cases cannot declare a raw type}}
82-
// expected-error@-2 {{raw type}}
8382
class mixed_redecl3b : mixed_redecl3 {} // expected-error {{'mixed_redecl3' is ambiguous for type lookup in this context}}
8483

8584
class mixed_redecl4 {} // expected-note {{previously declared here}}

0 commit comments

Comments
 (0)