Skip to content

Commit f762644

Browse files
committed
Diagnose nested type references with unsatisfied requirements
1 parent 26ceb28 commit f762644

File tree

2 files changed

+61
-15
lines changed

2 files changed

+61
-15
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -629,9 +629,9 @@ static bool isPointerToVoid(ASTContext &Ctx, Type Ty, bool &IsMutable) {
629629
return BGT->getGenericArgs().front()->isVoid();
630630
}
631631

632-
static Type checkConstrainedExtensionRequirements(Type type,
633-
SourceLoc loc,
634-
DeclContext *dc) {
632+
static Type checkContextualRequirements(Type type,
633+
SourceLoc loc,
634+
DeclContext *dc) {
635635
// Even if the type is not generic, it might be inside of a generic
636636
// context, so we need to check requirements.
637637
GenericTypeDecl *decl;
@@ -646,25 +646,34 @@ static Type checkConstrainedExtensionRequirements(Type type,
646646
return type;
647647
}
648648

649-
// FIXME: Some day the type might also have its own 'where' clause, even
650-
// if its not generic.
651-
652-
auto *ext = dyn_cast<ExtensionDecl>(decl->getDeclContext());
653-
if (!ext || !ext->isConstrainedExtension())
654-
return type;
655-
656-
if (parentTy->hasUnboundGenericType() ||
649+
if (!parentTy || parentTy->hasUnboundGenericType() ||
657650
parentTy->hasTypeVariable()) {
658651
return type;
659652
}
660653

661-
auto subMap = parentTy->getContextSubstitutions(ext);
654+
// We are interested in either a contextual where clause or
655+
// a constrained extension context.
656+
TypeSubstitutionMap subMap;
657+
GenericSignature genericSig;
658+
SourceLoc noteLoc;
659+
if (decl->getTrailingWhereClause()) {
660+
subMap = parentTy->getContextSubstitutions(decl->getDeclContext());
661+
genericSig = decl->getGenericSignature();
662+
noteLoc = decl->getLoc();
663+
} else {
664+
const auto ext = dyn_cast<ExtensionDecl>(decl->getDeclContext());
665+
if (ext && ext->isConstrainedExtension()) {
666+
subMap = parentTy->getContextSubstitutions(ext);
667+
genericSig = ext->getGenericSignature();
668+
noteLoc = ext->getLoc();
669+
} else {
670+
return type;
671+
}
672+
}
662673

663-
SourceLoc noteLoc = ext->getLoc();
664674
if (noteLoc.isInvalid())
665675
noteLoc = loc;
666676

667-
auto genericSig = ext->getGenericSignature();
668677
auto result =
669678
TypeChecker::checkGenericArguments(
670679
dc, loc, noteLoc, type,
@@ -722,7 +731,7 @@ static Type applyGenericArguments(Type type,
722731
if (resolution.getStage() == TypeResolutionStage::Structural)
723732
return type;
724733

725-
return checkConstrainedExtensionRequirements(type, loc, dc);
734+
return checkContextualRequirements(type, loc, dc);
726735
}
727736

728737
if (type->hasError()) {

test/Generics/where_clause_contextually_generic_decls.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,40 @@ func testMemberDeclarations<T, U: Comparable>(arg1: Class<T>, arg2: Class<U>) {
105105
arg1[] // expected-error {{subscript 'subscript()' requires that 'T' conform to 'Sequence'}}
106106
_ = Class<Array<Int>>()[Int.zero]
107107
}
108+
109+
// Test nested types and requirements.
110+
111+
struct Container<T> {
112+
typealias NestedAlias = Bool where T == Int
113+
// expected-note@-1 {{'NestedAlias' previously declared here}}
114+
typealias NestedAlias = Bool where T == Bool
115+
// expected-error@-1 {{invalid redeclaration of 'NestedAlias}}
116+
typealias NestedAlias2 = T.Magnitude where T: FixedWidthInteger
117+
118+
class NestedClass where T: Equatable {}
119+
}
120+
121+
extension Container where T: Sequence {
122+
struct NestedStruct {}
123+
124+
struct NestedStruct2 where T.Element: Comparable {
125+
enum NestedEnum where T.Element == Double {} // expected-note {{requirement specified as 'T.Element' == 'Double' [with T = String]}}
126+
}
127+
128+
struct NestedStruct3<U: Whereable> {}
129+
}
130+
131+
extension Container.NestedStruct3 {
132+
func foo(arg: U) where U.Assoc == T {}
133+
}
134+
135+
_ = Container<String>.NestedAlias2.self // expected-error {{type 'String' does not conform to protocol 'FixedWidthInteger'}}
136+
_ = Container<Container<Bool>>.NestedClass.self // expected-error {{type 'Container<Bool>' does not conform to protocol 'Equatable'}}
137+
_ = Container<Void>.NestedStruct.self // expected-error {{type 'Void' does not conform to protocol 'Sequence'}}
138+
_ = Container<Array<Void>>.NestedStruct2.self // expected-error {{type 'Void' does not conform to protocol 'Comparable'}}
139+
_ = Container<String>.NestedStruct2.NestedEnum.self // expected-error {{'Container<String>.NestedStruct2.NestedEnum' requires the types 'String.Element' (aka 'Character') and 'Double' be equivalent}}
140+
_ = Container<Int>.NestedAlias2.self
141+
_ = Container<Bool>.NestedClass.self
142+
_ = Container<String>.NestedStruct.self
143+
_ = Container<Array<UInt8>>.NestedStruct2.self
144+
_ = Container<Array<Double>>.NestedStruct2.NestedEnum.self

0 commit comments

Comments
 (0)