Merge pull request #26690 from varungandhi-apple/vg-refactor-validateExtension

Avoid setting the extendedType before and after computing the generic signature.
This commit is contained in:
Varun Gandhi
2019-08-19 14:04:03 -07:00
committed by GitHub
12 changed files with 107 additions and 78 deletions

View File

@@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 511; // ctor failability change
const uint16_t SWIFTMODULE_VERSION_MINOR = 512; // extended types may be left as unbound generic types
using DeclIDField = BCFixed<31>;

View File

@@ -4451,7 +4451,7 @@ static Type formExtensionInterfaceType(
/// Check the generic parameters of an extension, recursively handling all of
/// the parameter lists within the extension.
static std::pair<GenericEnvironment *, Type>
static GenericEnvironment *
checkExtensionGenericParams(TypeChecker &tc, ExtensionDecl *ext, Type type,
GenericParamList *genericParams) {
assert(!ext->getGenericEnvironment());
@@ -4489,7 +4489,7 @@ checkExtensionGenericParams(TypeChecker &tc, ExtensionDecl *ext, Type type,
(mustInferRequirements ||
!sameTypeReqs.empty()));
return { env, extInterfaceType };
return env;
}
static bool isNonGenericTypeAliasType(Type type) {
@@ -4500,69 +4500,65 @@ static bool isNonGenericTypeAliasType(Type type) {
return false;
}
static void validateExtendedType(ExtensionDecl *ext, TypeChecker &tc) {
// If we didn't parse a type, fill in an error type and bail out.
if (!ext->getExtendedTypeLoc().getTypeRepr()) {
static Type validateExtendedType(ExtensionDecl *ext) {
auto error = [&ext]() {
ext->setInvalid();
ext->getExtendedTypeLoc().setInvalidType(tc.Context);
return;
}
return ErrorType::get(ext->getASTContext());
};
// Validate the extended type.
// If we didn't parse a type, fill in an error type and bail out.
if (!ext->getExtendedTypeLoc().getTypeRepr())
return error();
// Compute the extended type.
TypeResolutionOptions options(TypeResolverContext::ExtensionBinding);
options |= TypeResolutionFlags::AllowUnboundGenerics;
if (tc.validateType(ext->getExtendedTypeLoc(),
TypeResolution::forInterface(ext->getDeclContext()),
options)) {
ext->setInvalid();
ext->getExtendedTypeLoc().setInvalidType(tc.Context);
return;
}
auto tr = TypeResolution::forStructural(ext->getDeclContext());
auto extendedType = tr.resolveType(ext->getExtendedTypeLoc().getTypeRepr(),
options);
ext->getExtendedTypeLoc().setType(extendedType);
// Dig out the extended type.
auto extendedType = ext->getExtendedType();
if (extendedType->hasError())
return error();
// Hack to allow extending a generic typealias.
if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) {
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) {
auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal();
if (extendedNominal) {
extendedType = extendedNominal->getDeclaredType();
if (!isPassThroughTypealias(aliasDecl))
ext->getExtendedTypeLoc().setType(extendedType);
}
if (extendedNominal)
return isPassThroughTypealias(aliasDecl)
? extendedType
: extendedNominal->getDeclaredType();
}
}
auto &diags = ext->getASTContext().Diags;
// Cannot extend a metatype.
if (extendedType->is<AnyMetatypeType>()) {
tc.diagnose(ext->getLoc(), diag::extension_metatype, extendedType)
diags.diagnose(ext->getLoc(), diag::extension_metatype, extendedType)
.highlight(ext->getExtendedTypeLoc().getSourceRange());
ext->setInvalid();
ext->getExtendedTypeLoc().setInvalidType(tc.Context);
return;
return error();
}
// Cannot extend function types, tuple types, etc.
if (!extendedType->getAnyNominal()) {
tc.diagnose(ext->getLoc(), diag::non_nominal_extension, extendedType)
diags.diagnose(ext->getLoc(), diag::non_nominal_extension, extendedType)
.highlight(ext->getExtendedTypeLoc().getSourceRange());
ext->setInvalid();
ext->getExtendedTypeLoc().setInvalidType(tc.Context);
return;
return error();
}
// Cannot extend a bound generic type, unless it's referenced via a
// non-generic typealias type.
if (extendedType->isSpecialized() &&
!isNonGenericTypeAliasType(extendedType)) {
tc.diagnose(ext->getLoc(), diag::extension_specialization,
diags.diagnose(ext->getLoc(), diag::extension_specialization,
extendedType->getAnyNominal()->getName())
.highlight(ext->getExtendedTypeLoc().getSourceRange());
ext->setInvalid();
ext->getExtendedTypeLoc().setInvalidType(tc.Context);
return;
return error();
}
return extendedType;
}
void TypeChecker::validateExtension(ExtensionDecl *ext) {
@@ -4573,7 +4569,7 @@ void TypeChecker::validateExtension(ExtensionDecl *ext) {
DeclValidationRAII IBV(ext);
validateExtendedType(ext, *this);
auto extendedType = validateExtendedType(ext);
if (auto *nominal = ext->getExtendedNominal()) {
// If this extension was not already bound, it means it is either in an
@@ -4586,14 +4582,11 @@ void TypeChecker::validateExtension(ExtensionDecl *ext) {
// Validate the nominal type declaration being extended.
validateDecl(nominal);
if (auto *genericParams = ext->getGenericParams()) {
GenericEnvironment *env;
Type extendedType = ext->getExtendedType();
std::tie(env, extendedType) = checkExtensionGenericParams(
*this, ext, extendedType,
genericParams);
ext->getExtendedTypeLoc().setType(extendedType);
if (auto *genericParams = ext->getGenericParams()) {
GenericEnvironment *env =
checkExtensionGenericParams(*this, ext, extendedType, genericParams);
ext->setGenericEnvironment(env);
}
}

View File

@@ -76,7 +76,7 @@ static void checkGenericParamList(TypeChecker &tc,
if (auto decl = owner.dc->getAsDecl()) {
if (auto extDecl = dyn_cast<ExtensionDecl>(decl)) {
auto extType = extDecl->getExtendedType();
auto extType = extDecl->getDeclaredInterfaceType();
auto extSelfType = extDecl->getSelfInterfaceType();
auto reqLHSType = req.getFirstType();
auto reqRHSType = req.getSecondType();

View File

@@ -536,11 +536,20 @@ Type TypeChecker::resolveTypeInContext(
parentDC = parentDC->getParent()) {
if (auto *ext = dyn_cast<ExtensionDecl>(parentDC)) {
auto extendedType = ext->getExtendedType();
if (auto *aliasType = dyn_cast<TypeAliasType>(extendedType.getPointer())) {
if (aliasType->getDecl() == aliasDecl) {
if (auto *unboundGeneric = dyn_cast<UnboundGenericType>(extendedType.getPointer())) {
if (auto *ugAliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getAnyGeneric())) {
if (ugAliasDecl == aliasDecl)
return resolution.mapTypeIntoContext(
aliasDecl->getDeclaredInterfaceType());
extendedType = unboundGeneric->getParent();
continue;
}
}
if (auto *aliasType = dyn_cast<TypeAliasType>(extendedType.getPointer())) {
if (aliasType->getDecl() == aliasDecl)
return resolution.mapTypeIntoContext(
aliasDecl->getDeclaredInterfaceType());
extendedType = aliasType->getParent();
continue;

View File

@@ -3931,9 +3931,8 @@ public:
MF.configureGenericEnvironment(extension, genericEnvID);
auto baseTy = MF.getType(baseID);
auto nominal = baseTy->getAnyNominal();
assert(!baseTy->hasUnboundGenericType());
extension->getExtendedTypeLoc().setType(baseTy);
auto nominal = extension->getExtendedNominal();
if (isImplicit)
extension->setImplicit();

View File

@@ -2871,7 +2871,6 @@ public:
auto contextID = S.addDeclContextRef(extension->getDeclContext());
Type baseTy = extension->getExtendedType();
assert(!baseTy->hasUnboundGenericType());
assert(!baseTy->hasArchetype());
// FIXME: Use the canonical type here in order to minimize circularity

View File

@@ -73,7 +73,7 @@ struct NonRecur: P2 {
// Conditional conformance.
struct Generic<T> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Generic<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Generic
// CHECK-NEXT: (normal_conformance type=Generic<T> protocol=P1
// CHECK-NEXT: (assoc_type req=A type=T)
// CHECK-NEXT: (value req=f() witness=main.(file).Generic extension.f()@{{.*}})
@@ -86,7 +86,7 @@ extension Generic: P1 where T: P1 {
// Satisfying associated types with requirements with generic params
class Super<T, U> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Super<T, U>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Super
// CHECK-NEXT: (normal_conformance type=Super<T, U> protocol=P2
// CHECK-NEXT: (assoc_type req=A type=T)
// CHECK-NEXT: (assoc_type req=B type=T)

View File

@@ -21,7 +21,7 @@ func takes_P2<X: P2>(_: X) {}
func takes_P5<X: P5>(_: X) {}
struct Free<T> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Free<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Free
// CHECK-NEXT: (normal_conformance type=Free<T> protocol=P2
// CHECK-NEXT: conforms_to: T P1)
extension Free: P2 where T: P1 {} // expected-note {{requirement from conditional conformance of 'Free<U>' to 'P2'}}
@@ -33,7 +33,7 @@ func free_bad<U>(_: U) {
}
struct Constrained<T: P1> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Constrained<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Constrained
// CHECK-NEXT: (normal_conformance type=Constrained<T> protocol=P2
// CHECK-NEXT: conforms_to: T P3)
extension Constrained: P2 where T: P3 {} // expected-note {{requirement from conditional conformance of 'Constrained<U>' to 'P2'}}
@@ -45,17 +45,17 @@ func constrained_bad<U: P1>(_: U) {
}
struct RedundantSame<T: P1> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSame<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSame
// CHECK-NEXT: (normal_conformance type=RedundantSame<T> protocol=P2)
extension RedundantSame: P2 where T: P1 {}
struct RedundantSuper<T: P4> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSuper<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSuper
// CHECK-NEXT: (normal_conformance type=RedundantSuper<T> protocol=P2)
extension RedundantSuper: P2 where T: P1 {}
struct OverlappingSub<T: P1> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=OverlappingSub<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=OverlappingSub
// CHECK-NEXT: (normal_conformance type=OverlappingSub<T> protocol=P2
// CHECK-NEXT: conforms_to: T P4)
extension OverlappingSub: P2 where T: P4 {} // expected-note {{requirement from conditional conformance of 'OverlappingSub<U>' to 'P2'}}
@@ -68,7 +68,7 @@ func overlapping_sub_bad<U: P1>(_: U) {
struct SameType<T> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=SameType<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=SameType
// CHECK-NEXT: (normal_conformance type=SameType<T> protocol=P2
// CHECK-NEXT: same_type: T Int)
extension SameType: P2 where T == Int {}
@@ -84,7 +84,7 @@ func same_type_bad<U>(_: U) {
struct SameTypeGeneric<T, U> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=SameTypeGeneric<T, U>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=SameTypeGeneric
// CHECK-NEXT: (normal_conformance type=SameTypeGeneric<T, U> protocol=P2
// CHECK-NEXT: same_type: T U)
extension SameTypeGeneric: P2 where T == U {}
@@ -108,7 +108,7 @@ func same_type_bad<U, V>(_: U, _: V) {
struct Infer<T, U> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Infer<T, U>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=Infer
// CHECK-NEXT: (normal_conformance type=Infer<T, U> protocol=P2
// CHECK-NEXT: same_type: T Constrained<U>
// CHECK-NEXT: conforms_to: U P1)
@@ -126,7 +126,7 @@ func infer_bad<U: P1, V>(_: U, _: V) {
}
struct InferRedundant<T, U: P1> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InferRedundant<T, U>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InferRedundant
// CHECK-NEXT: (normal_conformance type=InferRedundant<T, U> protocol=P2
// CHECK-NEXT: same_type: T Constrained<U>)
extension InferRedundant: P2 where T == Constrained<U> {}
@@ -146,7 +146,7 @@ class C2: C1 {}
class C3: C2 {}
struct ClassFree<T> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=ClassFree<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=ClassFree
// CHECK-NEXT: (normal_conformance type=ClassFree<T> protocol=P2
// CHECK-NEXT: superclass: T C1)
extension ClassFree: P2 where T: C1 {}
@@ -159,7 +159,7 @@ func class_free_bad<U>(_: U) {
}
struct ClassMoreSpecific<T: C1> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=ClassMoreSpecific<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=ClassMoreSpecific
// CHECK-NEXT: (normal_conformance type=ClassMoreSpecific<T> protocol=P2
// CHECK-NEXT: superclass: T C3)
extension ClassMoreSpecific: P2 where T: C3 {} // expected-note {{requirement from conditional conformance of 'ClassMoreSpecific<U>' to 'P2'}}
@@ -173,7 +173,7 @@ func class_more_specific_bad<U: C1>(_: U) {
struct ClassLessSpecific<T: C3> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=ClassLessSpecific<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=ClassLessSpecific
// CHECK-NEXT: (normal_conformance type=ClassLessSpecific<T> protocol=P2)
extension ClassLessSpecific: P2 where T: C1 {}
@@ -195,11 +195,11 @@ func subclass_bad() {
// Inheriting conformances:
struct InheritEqual<T> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InheritEqual<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InheritEqual
// CHECK-NEXT: (normal_conformance type=InheritEqual<T> protocol=P2
// CHECK-NEXT: conforms_to: T P1)
extension InheritEqual: P2 where T: P1 {} // expected-note {{requirement from conditional conformance of 'InheritEqual<U>' to 'P2'}}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InheritEqual<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InheritEqual
// CHECK-NEXT: (normal_conformance type=InheritEqual<T> protocol=P5
// CHECK-NEXT: (normal_conformance type=InheritEqual<T> protocol=P2
// CHECK-NEXT: conforms_to: T P1)
@@ -223,11 +223,11 @@ extension InheritLess: P5 {} // expected-error{{type 'T' does not conform to pro
struct InheritMore<T> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InheritMore<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InheritMore
// CHECK-NEXT: (normal_conformance type=InheritMore<T> protocol=P2
// CHECK-NEXT: conforms_to: T P1)
extension InheritMore: P2 where T: P1 {} // expected-note {{requirement from conditional conformance of 'InheritMore<U>' to 'P2'}}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InheritMore<T>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=InheritMore
// CHECK-NEXT: (normal_conformance type=InheritMore<T> protocol=P5
// CHECK-NEXT: (normal_conformance type=InheritMore<T> protocol=P2
// CHECK-NEXT: conforms_to: T P1)
@@ -310,12 +310,12 @@ extension TwoDisjointConformances: P2 where T == String {}
// signature, meaning the stored conditional requirement is T: P1, which isn't
// true in the original type's generic signature.
struct RedundancyOrderDependenceGood<T: P1, U> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceGood<T, U>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceGood
// CHECK-NEXT: (normal_conformance type=RedundancyOrderDependenceGood<T, U> protocol=P2
// CHECK-NEXT: same_type: T U)
extension RedundancyOrderDependenceGood: P2 where U: P1, T == U {}
struct RedundancyOrderDependenceBad<T, U: P1> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceBad<T, U>
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceBad
// CHECK-NEXT: (normal_conformance type=RedundancyOrderDependenceBad<T, U> protocol=P2
// CHECK-NEXT: conforms_to: T P1
// CHECK-NEXT: same_type: T U)

View File

@@ -0,0 +1,10 @@
struct S {}
extension S : P2 {}
extension S : P1_1 {}
func f() {
let s = S.init()
s.p1_1()
}

View File

@@ -0,0 +1,19 @@
// XFAIL: *
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -primary-file %s %S/Inputs/composition_extensions_usage.swift -emit-module-path %t/P-partial.swiftmodule -module-name SR11227 -enable-testing
// RUN: %target-swift-frontend -primary-file %S/Inputs/composition_extensions_usage.swift %s -emit-module-path %t/S-partial.swiftmodule -module-name SR11227 -enable-testing
// RUN: %target-swift-frontend -sil-merge-partial-modules %t/P-partial.swiftmodule %t/S-partial.swiftmodule -emit-module -o %t/SR11227.swiftmodule
protocol P0 {}
protocol P1 {}
protocol P1_1 : P1 {
func p1_1()
}
protocol P2 {}
extension P1 & P1_1 where Self : P2 {
func p1_1() {}
}

View File

@@ -21,13 +21,13 @@ extension Zahl {
public typealias List<T> = Array<T>
// CHECK-LABEL: extension Array {
// CHECK-LABEL: extension List {
extension List {
// CHECK-NEXT: addedMember()
public func addedMember() {}
} // CHECK-NEXT: {{^}$}}
// CHECK-LABEL: extension Array where Element == Int {
// CHECK-LABEL: extension List where Element == Int {
extension List where Element == Int {
// CHECK-NEXT: addedMemberInt()
public func addedMemberInt() {}

View File

@@ -22,7 +22,7 @@ extension MyNonGenericType {}
// CHECK-DAG: typealias MyGenericType<T> = GenericType<T>
typealias MyGenericType<T: NSObject> = GenericType<T>
// CHECK-DAG: extension GenericType where Element : NSObject
// CHECK-DAG: extension MyGenericType where Element : NSObject
extension MyGenericType {}
// CHECK-DAG: extension GenericType where Element == NSObject
// CHECK-DAG: extension MyGenericType where Element == NSObject
extension MyGenericType where Element == NSObject {}