Skip to content

Commit

Permalink
Sema: Allow extensions to make generic parameters concrete via same-t…
Browse files Browse the repository at this point in the history
…ype constraints

Fixes <https://bugs.swift.org/browse/SR-1009>.
  • Loading branch information
slavapestov committed Oct 5, 2016
1 parent 8bf32c5 commit 8f88d19
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 21 deletions.
3 changes: 2 additions & 1 deletion lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1817,7 +1817,8 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
unsigned disambiguatedNameCounter = 1;
for (auto *paramTy : sig->getGenericParams()) {
auto *archetypeTy = mapTypeIntoContext(paramTy)->getAs<ArchetypeType>();
assert(archetypeTy);
if (!archetypeTy)
continue;

Identifier name = archetypeTy->getName();
while (!UsedNames.insert(name).second) {
Expand Down
31 changes: 24 additions & 7 deletions lib/SIL/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1678,11 +1678,10 @@ TypeConverter::getEffectiveGenericEnvironment(AnyFunctionRef fn,
CaptureInfo captureInfo) {
auto dc = fn.getAsDeclContext();

if (dc->getParent()->isLocalContext() &&
!captureInfo.hasGenericParamCaptures())
return nullptr;
if (getEffectiveGenericSignature(fn, captureInfo))
return dc->getGenericEnvironmentOfContext();

return dc->getGenericEnvironmentOfContext();
return nullptr;
}

CanGenericSignature
Expand All @@ -1694,8 +1693,11 @@ TypeConverter::getEffectiveGenericSignature(AnyFunctionRef fn,
!captureInfo.hasGenericParamCaptures())
return nullptr;

if (auto sig = dc->getGenericSignatureOfContext())
if (auto sig = dc->getGenericSignatureOfContext()) {
if (sig->areAllParamsConcrete())
return nullptr;
return sig->getCanonicalSignature();
}

return nullptr;
}
Expand Down Expand Up @@ -1990,18 +1992,33 @@ getMaterializeForSetCallbackType(AbstractStorageDecl *storage,
}
}

CanType canSelfType;
CanType canSelfMetatypeType;
if (genericSig) {
canSelfType = genericSig->getCanonicalTypeInContext(
selfType, *M.getSwiftModule());
canSelfMetatypeType = genericSig->getCanonicalTypeInContext(
selfMetatypeType, *M.getSwiftModule());
} else {
canSelfType = selfType->getCanonicalType();
canSelfMetatypeType = selfMetatypeType->getCanonicalType();
}

// Create the SILFunctionType for the callback.
SILParameterInfo params[] = {
{ ctx.TheRawPointerType, ParameterConvention::Direct_Unowned },
{ ctx.TheUnsafeValueBufferType, ParameterConvention::Indirect_Inout },
{ selfType->getCanonicalType(), ParameterConvention::Indirect_Inout },
{ selfMetatypeType->getCanonicalType(), ParameterConvention::Direct_Unowned },
{ canSelfType, ParameterConvention::Indirect_Inout },
{ canSelfMetatypeType, ParameterConvention::Direct_Unowned },
};
ArrayRef<SILResultInfo> results = {};
auto extInfo =
SILFunctionType::ExtInfo()
.withRepresentation(SILFunctionTypeRepresentation::Thin);

if (genericSig && genericSig->areAllParamsConcrete())
genericSig = nullptr;

return SILFunctionType::get(genericSig, extInfo,
/*callee*/ ParameterConvention::Direct_Unowned,
params, results, None, ctx);
Expand Down
17 changes: 8 additions & 9 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1044,20 +1044,19 @@ void ConstraintSystem::openGeneric(
ConstraintLocatorBuilder locator,
llvm::DenseMap<CanType, TypeVariableType *> &replacements) {
auto locatorPtr = getConstraintLocator(locator);

auto *genericEnv = innerDC->getGenericEnvironmentOfContext();

// Create the type variables for the generic parameters.
for (auto gp : params) {
auto contextTy = genericEnv->mapTypeIntoContext(gp);
if (auto *archetype = contextTy->getAs<ArchetypeType>()) {
auto typeVar = createTypeVariable(getConstraintLocator(
locator.withPathElement(
LocatorPathElt(archetype))),
TVO_PrefersSubtypeBinding |
TVO_MustBeMaterializable);
replacements[gp->getCanonicalType()] = typeVar;
}
if (auto *archetype = contextTy->getAs<ArchetypeType>())
locatorPtr = getConstraintLocator(
locator.withPathElement(LocatorPathElt(archetype)));

auto typeVar = createTypeVariable(locatorPtr,
TVO_PrefersSubtypeBinding |
TVO_MustBeMaterializable);
replacements[gp->getCanonicalType()] = typeVar;
}

GetTypeVariable getTypeVariable{*this, locator};
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7548,7 +7548,7 @@ static Type checkExtensionGenericParams(
auto *parentEnv = ext->getDeclContext()->getGenericEnvironmentOfContext();
auto *sig = tc.validateGenericSignature(genericParams,
ext->getDeclContext(), parentSig,
/*allowConcreteGenericParams=*/false,
/*allowConcreteGenericParams=*/true,
inferExtendedTypeReqs, invalid);
ext->setGenericSignature(sig);

Expand Down
117 changes: 117 additions & 0 deletions test/SILGen/constrained_extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
// RUN: %target-swift-frontend -emit-ir %s
// RUN: %target-swift-frontend -emit-ir -O %s

extension Array where Element == Int {
// CHECK-LABEL: sil @_TFe22constrained_extensionsRxzSirSag16instancePropertySi : $@convention(method) (@guaranteed Array<Int>) -> Int
// CHECK-LABEL: sil @_TFe22constrained_extensionsRxzSirSas16instancePropertySi : $@convention(method) (Int, @inout Array<Int>) -> ()
// CHECK-LABEL: sil [transparent] [fragile] @_TFe22constrained_extensionsRxzSirSam16instancePropertySi : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array<Int>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
// CHECK-LABEL: sil [transparent] [fragile] @_TFFe22constrained_extensionsRxzSirSam16instancePropertySiU_T_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array<Int>, @thick Array<Int>.Type) -> ()
public var instanceProperty: Element {
get {
return self[0]
}
set {
self[0] = newValue
}
}

// CHECK-LABEL: sil @_TFe22constrained_extensionsRxzSirSa14instanceMethodfT_x : $@convention(method) (@guaranteed Array<Int>) -> Int
public func instanceMethod() -> Element {
return instanceProperty
}

// CHECK-LABEL: sil @_TFe22constrained_extensionsRxzSirSa14instanceMethodfT1ex_x : $@convention(method) (Int, @guaranteed Array<Int>) -> Int
public func instanceMethod(e: Element) -> Element {
return e
}

// CHECK-LABEL: sil @_TZFe22constrained_extensionsRxzSirSag14staticPropertySi : $@convention(method) (@thin Array<Int>.Type) -> Int
public static var staticProperty: Element {
return 0
}

// CHECK-LABEL: sil @_TZFe22constrained_extensionsRxzSirSa12staticMethodfT_x : $@convention(method) (@thin Array<Int>.Type) -> Int
public static func staticMethod() -> Element {
return staticProperty
}

// CHECK-LABEL: sil @_TIZFe22constrained_extensionsRxzSirSa12staticMethodFT1eGSqx__xA_ : $@convention(thin) () -> Optional<Int>
// CHECK-LABEL: sil @_TZFe22constrained_extensionsRxzSirSa12staticMethodfT1eGSqx__x : $@convention(method) (Optional<Int>, @thin Array<Int>.Type) -> Int
public static func staticMethod(e: Element? = nil) -> Element {
return e!
}

// CHECK-LABEL: sil @_TFe22constrained_extensionsRxzSirSag9subscriptFT_Si : $@convention(method) (@guaranteed Array<Int>) -> Int
public subscript(i: ()) -> Element {
return self[0]
}

// CHECK-LABEL: sil @_TFe22constrained_extensionsRxzSirSa21inoutAccessOfPropertyfT_T_ : $@convention(method) (@inout Array<Int>) -> ()
public mutating func inoutAccessOfProperty() {
func increment(x: inout Element) {
x += 1
}

increment(x: &instanceProperty)
}
}

extension Dictionary where Key == Int {
// CHECK-LABEL: sil @_TFe22constrained_extensions0_RxzSirVs10Dictionaryg16instancePropertyq_ : $@convention(method) <Int, Value where Int == Int> (@guaranteed Dictionary<Int, Value>) -> @out Value
// CHECK-LABEL: sil @_TFe22constrained_extensions0_RxzSirVs10Dictionarys16instancePropertyq_ : $@convention(method) <Int, Value where Int == Int> (@in Value, @inout Dictionary<Int, Value>) -> ()
// CHECK-LABEL: sil [transparent] [fragile] @_TFe22constrained_extensions0_RxzSirVs10Dictionarym16instancePropertyq_ : $@convention(method) <Int, Value where Int == Int> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary<Int, Value>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
// CHECK-LABEL: sil [transparent] [fragile] @_TFFe22constrained_extensions0_RxzSirVs10Dictionarym16instancePropertyq_U_T_ : $@convention(thin) <Int, Value where Int == Int> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary<Int, Value>, @thick Dictionary<Int, Value>.Type) -> ()
public var instanceProperty: Value {
get {
return self[0]!
}
set {
self[0] = newValue
}
}

// CHECK-LABEL: sil @_TFe22constrained_extensions0_RxzSirVs10Dictionary14instanceMethodfT_q_ : $@convention(method) <Int, Value where Int == Int> (@guaranteed Dictionary<Int, Value>) -> @out Value
public func instanceMethod() -> Value {
return instanceProperty
}

// CHECK-LABEL: sil @_TFe22constrained_extensions0_RxzSirVs10Dictionary14instanceMethodfT1vq__q_ : $@convention(method) <Int, Value where Int == Int> (@in Value, @guaranteed Dictionary<Int, Value>) -> @out Value
public func instanceMethod(v: Value) -> Value {
return v
}

// CHECK-LABEL: sil @_TZFe22constrained_extensions0_RxzSirVs10Dictionary12staticMethodfT_x : $@convention(method) <Int, Value where Int == Int> (@thin Dictionary<Int, Value>.Type) -> Int
public static func staticMethod() -> Key {
return staticProperty
}

// CHECK-LABEL: sil @_TZFe22constrained_extensions0_RxzSirVs10Dictionaryg14staticPropertySi : $@convention(method) <Int, Value where Int == Int> (@thin Dictionary<Int, Value>.Type) -> Int
public static var staticProperty: Key {
return 0
}

// CHECK-LABEL: sil @_TIZFe22constrained_extensions0_RxzSirVs10Dictionary12staticMethodFT1kGSqx_1vGSqq___q_A_ : $@convention(thin) <Int, Value where Int == Int> () -> Optional<Int>
// CHECK-LABEL: sil @_TIZFe22constrained_extensions0_RxzSirVs10Dictionary12staticMethodFT1kGSqx_1vGSqq___q_A0_ : $@convention(thin) <Int, Value where Int == Int> () -> @out Optional<Value>
// CHECK-LABEL: sil @_TZFe22constrained_extensions0_RxzSirVs10Dictionary12staticMethodfT1kGSqx_1vGSqq___q_ : $@convention(method) <Int, Value where Int == Int> (Optional<Int>, @in Optional<Value>, @thin Dictionary<Int, Value>.Type) -> @out Value
public static func staticMethod(k: Key? = nil, v: Value? = nil) -> Value {
return v!
}

// CHECK-LABEL: sil @_TZFe22constrained_extensions0_RxzSirVs10Dictionary17callsStaticMethodfT_q_ : $@convention(method) <Int, Value where Int == Int> (@thin Dictionary<Int, Value>.Type) -> @out Value
public static func callsStaticMethod() -> Value {
return staticMethod()
}

// CHECK-LABEL: sil @_TFe22constrained_extensions0_RxzSirVs10Dictionaryg9subscriptFT_q_ : $@convention(method) <Int, Value where Int == Int> (@guaranteed Dictionary<Int, Value>) -> @out Value
public subscript(i: ()) -> Value {
return self[0]!
}

// CHECK-LABEL: sil @_TFe22constrained_extensions0_RxzSirVs10Dictionary21inoutAccessOfPropertyfT_T_ : $@convention(method) <Int, Value where Int == Int> (@inout Dictionary<Int, Value>) -> ()
public mutating func inoutAccessOfProperty() {
func increment(x: inout Value) { }

increment(x: &instanceProperty)
}
}
3 changes: 1 addition & 2 deletions test/decl/ext/generic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,7 @@ func genericClassNotEquatable<T>(_ gc: GenericClass<T>, x: T, y: T) {
}


// FIXME: Future direction
extension Array where Element == String { } // expected-error{{same-type requirement makes generic parameter 'Element' non-generic}}
extension Array where Element == String { }

extension GenericClass : P3 where T : P3 { } // expected-error{{extension of type 'GenericClass' with constraints cannot have an inheritance clause}}

Expand Down
1 change: 0 additions & 1 deletion test/decl/var/properties.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,6 @@ extension rdar17391625derived {
public protocol rdar27671033P {}
struct rdar27671033S<Key, Value> {}
extension rdar27671033S : rdar27671033P where Key == String { // expected-error {{extension of type 'rdar27671033S' with constraints cannot have an inheritance clause}}
// expected-error@-1 {{same-type requirement makes generic parameter 'Key' non-generic}}
let d = rdar27671033S<Int, Int>() // expected-error {{extensions may not contain stored properties}}
}

Expand Down

1 comment on commit 8f88d19

@lattner
Copy link
Contributor

@lattner lattner commented on 8f88d19 Oct 5, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, please update the changelog and send a note to swift-dev, asking people to kick the tires!

Please sign in to comment.