diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index e0ffe53d8327c..f315fae69d82a 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -629,9 +629,9 @@ static bool isPointerToVoid(ASTContext &Ctx, Type Ty, bool &IsMutable) { return BGT->getGenericArgs().front()->isVoid(); } -static Type checkConstrainedExtensionRequirements(Type type, - SourceLoc loc, - DeclContext *dc) { +static Type checkContextualRequirements(Type type, + SourceLoc loc, + DeclContext *dc) { // Even if the type is not generic, it might be inside of a generic // context, so we need to check requirements. GenericTypeDecl *decl; @@ -646,25 +646,34 @@ static Type checkConstrainedExtensionRequirements(Type type, return type; } - // FIXME: Some day the type might also have its own 'where' clause, even - // if its not generic. - - auto *ext = dyn_cast(decl->getDeclContext()); - if (!ext || !ext->isConstrainedExtension()) - return type; - - if (parentTy->hasUnboundGenericType() || + if (!parentTy || parentTy->hasUnboundGenericType() || parentTy->hasTypeVariable()) { return type; } - auto subMap = parentTy->getContextSubstitutions(ext); + // We are interested in either a contextual where clause or + // a constrained extension context. + TypeSubstitutionMap subMap; + GenericSignature genericSig; + SourceLoc noteLoc; + if (decl->getTrailingWhereClause()) { + subMap = parentTy->getContextSubstitutions(decl->getDeclContext()); + genericSig = decl->getGenericSignature(); + noteLoc = decl->getLoc(); + } else { + const auto ext = dyn_cast(decl->getDeclContext()); + if (ext && ext->isConstrainedExtension()) { + subMap = parentTy->getContextSubstitutions(ext); + genericSig = ext->getGenericSignature(); + noteLoc = ext->getLoc(); + } else { + return type; + } + } - SourceLoc noteLoc = ext->getLoc(); if (noteLoc.isInvalid()) noteLoc = loc; - auto genericSig = ext->getGenericSignature(); auto result = TypeChecker::checkGenericArguments( dc, loc, noteLoc, type, @@ -722,7 +731,7 @@ static Type applyGenericArguments(Type type, if (resolution.getStage() == TypeResolutionStage::Structural) return type; - return checkConstrainedExtensionRequirements(type, loc, dc); + return checkContextualRequirements(type, loc, dc); } if (type->hasError()) { diff --git a/test/Generics/where_clause_contextually_generic_decls.swift b/test/Generics/where_clause_contextually_generic_decls.swift index 9905e3432d3e4..68c41b6c6d095 100644 --- a/test/Generics/where_clause_contextually_generic_decls.swift +++ b/test/Generics/where_clause_contextually_generic_decls.swift @@ -105,3 +105,40 @@ func testMemberDeclarations(arg1: Class, arg2: Class) { arg1[] // expected-error {{subscript 'subscript()' requires that 'T' conform to 'Sequence'}} _ = Class>()[Int.zero] } + +// Test nested types and requirements. + +struct Container { + typealias NestedAlias = Bool where T == Int + // expected-note@-1 {{'NestedAlias' previously declared here}} + typealias NestedAlias = Bool where T == Bool + // expected-error@-1 {{invalid redeclaration of 'NestedAlias}} + typealias NestedAlias2 = T.Magnitude where T: FixedWidthInteger + + class NestedClass where T: Equatable {} +} + +extension Container where T: Sequence { + struct NestedStruct {} + + struct NestedStruct2 where T.Element: Comparable { + enum NestedEnum where T.Element == Double {} // expected-note {{requirement specified as 'T.Element' == 'Double' [with T = String]}} + } + + struct NestedStruct3 {} +} + +extension Container.NestedStruct3 { + func foo(arg: U) where U.Assoc == T {} +} + +_ = Container.NestedAlias2.self // expected-error {{type 'String' does not conform to protocol 'FixedWidthInteger'}} +_ = Container>.NestedClass.self // expected-error {{type 'Container' does not conform to protocol 'Equatable'}} +_ = Container.NestedStruct.self // expected-error {{type 'Void' does not conform to protocol 'Sequence'}} +_ = Container>.NestedStruct2.self // expected-error {{type 'Void' does not conform to protocol 'Comparable'}} +_ = Container.NestedStruct2.NestedEnum.self // expected-error {{'Container.NestedStruct2.NestedEnum' requires the types 'String.Element' (aka 'Character') and 'Double' be equivalent}} +_ = Container.NestedAlias2.self +_ = Container.NestedClass.self +_ = Container.NestedStruct.self +_ = Container>.NestedStruct2.self +_ = Container>.NestedStruct2.NestedEnum.self