Skip to content

[Sema] Construct OpenedArchetypeType with a canonical existential type. #40925

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -5654,7 +5654,7 @@ class OpenedArchetypeType final : public ArchetypeType,
/// \param knownID When non-empty, the known ID of the archetype. When empty,
/// a fresh archetype with a unique ID will be opened.
static CanTypeWrapper<OpenedArchetypeType> get(
Type existential, Optional<UUID> knownID = None);
CanType existential, Optional<UUID> knownID = None);

/// Get or create an archetype that represents the opened type
/// of an existential value.
Expand All @@ -5665,20 +5665,20 @@ class OpenedArchetypeType final : public ArchetypeType,
/// \param knownID When non-empty, the known ID of the archetype. When empty,
/// a fresh archetype with a unique ID will be opened.
static CanTypeWrapper<OpenedArchetypeType> get(
Type existential, Type interfaceType, Optional<UUID> knownID = None);
CanType existential, Type interfaceType, Optional<UUID> knownID = None);

/// Create a new archetype that represents the opened type
/// of an existential value.
///
/// \param existential The existential type or existential metatype to open.
/// \param interfaceType The interface type represented by this archetype.
static CanType getAny(Type existential, Type interfaceType);
static CanType getAny(CanType existential, Type interfaceType);

/// Create a new archetype that represents the opened type
/// of an existential value.
///
/// \param existential The existential type or existential metatype to open.
static CanType getAny(Type existential);
static CanType getAny(CanType existential);

/// Retrieve the ID number of this opened existential.
UUID getOpenedExistentialID() const;
Expand Down
21 changes: 16 additions & 5 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4286,15 +4286,25 @@ CanTypeWrapper<OpenedArchetypeType> OpenedArchetypeType::getNew(
}

CanTypeWrapper<OpenedArchetypeType> OpenedArchetypeType::get(
Type existential, Optional<UUID> knownID) {
CanType existential, Optional<UUID> knownID) {
Type interfaceType = GenericTypeParamType::get(
/*isTypeSequence=*/false, 0, 0, existential->getASTContext());
return get(existential, interfaceType, knownID);
}

CanOpenedArchetypeType OpenedArchetypeType::get(Type existential,
CanOpenedArchetypeType OpenedArchetypeType::get(CanType existential,
Type interfaceType,
Optional<UUID> knownID) {
// FIXME: Opened archetypes can't be transformed because the
// the identity of the archetype has to be preserved. This
// means that simplifying an opened archetype in the constraint
// system to replace type variables with fixed types is not
// yet supported. For now, assert that an opened archetype never
// contains type variables to catch cases where type variables
// would be applied to the type-checked AST.
assert(!existential->hasTypeVariable() &&
"opened existentials containing type variables cannot be simplified");

auto &ctx = existential->getASTContext();
auto &openedExistentialEnvironments =
ctx.getImpl().OpenedExistentialEnvironments;
Expand Down Expand Up @@ -4327,17 +4337,18 @@ CanOpenedArchetypeType OpenedArchetypeType::get(Type existential,
}


CanType OpenedArchetypeType::getAny(Type existential, Type interfaceType) {
CanType OpenedArchetypeType::getAny(CanType existential, Type interfaceType) {
if (auto metatypeTy = existential->getAs<ExistentialMetatypeType>()) {
auto instanceTy = metatypeTy->getExistentialInstanceType();
auto instanceTy =
metatypeTy->getExistentialInstanceType()->getCanonicalType();
return CanMetatypeType::get(
OpenedArchetypeType::getAny(instanceTy, interfaceType));
}
assert(existential->isExistentialType());
return OpenedArchetypeType::get(existential, interfaceType);
}

CanType OpenedArchetypeType::getAny(Type existential) {
CanType OpenedArchetypeType::getAny(CanType existential) {
Type interfaceType = GenericTypeParamType::get(
/*isTypeSequence=*/false, 0, 0, existential->getASTContext());
return getAny(existential, interfaceType);
Expand Down
5 changes: 3 additions & 2 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5613,13 +5613,14 @@ SILBoxType::SILBoxType(ASTContext &C,
Type TypeBase::openAnyExistentialType(OpenedArchetypeType *&opened) {
assert(isAnyExistentialType());
if (auto metaty = getAs<ExistentialMetatypeType>()) {
opened = OpenedArchetypeType::get(metaty->getExistentialInstanceType());
opened = OpenedArchetypeType::get(
metaty->getExistentialInstanceType()->getCanonicalType());
if (metaty->hasRepresentation())
return MetatypeType::get(opened, metaty->getRepresentation());
else
return MetatypeType::get(opened);
}
opened = OpenedArchetypeType::get(this);
opened = OpenedArchetypeType::get(getCanonicalType());
return opened;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4100,7 +4100,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

if (!ExprType->getMetatypeInstanceType()->isAnyObject())
if (ExprType->isAnyExistentialType())
ExprType = OpenedArchetypeType::getAny(ExprType);
ExprType = OpenedArchetypeType::getAny(ExprType->getCanonicalType());

if (!IsSelfRefExpr && !IsSuperRefExpr && ExprType->getAnyNominal() &&
ExprType->getAnyNominal()->isActor()) {
Expand Down
4 changes: 2 additions & 2 deletions lib/SILGen/SILGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ static ManagedValue emitCastToReferenceType(SILGenFunction &SGF,

// If the argument is existential, open it.
if (argTy->isClassExistentialType()) {
auto openedTy = OpenedArchetypeType::get(argTy);
auto openedTy = OpenedArchetypeType::get(argTy->getCanonicalType());
SILType loweredOpenedTy = SGF.getLoweredLoadableType(openedTy);
arg = SGF.B.createOpenExistentialRef(loc, arg, loweredOpenedTy);
}
Expand Down Expand Up @@ -790,7 +790,7 @@ static ManagedValue emitBuiltinCastToBridgeObject(SILGenFunction &SGF,

// If the argument is existential, open it.
if (sourceType->isClassExistentialType()) {
auto openedTy = OpenedArchetypeType::get(sourceType);
auto openedTy = OpenedArchetypeType::get(sourceType->getCanonicalType());
SILType loweredOpenedTy = SGF.getLoweredLoadableType(openedTy);
ref = SGF.B.createOpenExistentialRef(loc, ref, loweredOpenedTy);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1850,7 +1850,8 @@ RValue RValueEmitter::visitErasureExpr(ErasureExpr *E, SGFContext C) {
auto &existentialTL = SGF.getTypeLowering(E->getType());
auto concreteFormalType = E->getSubExpr()->getType()->getCanonicalType();

auto archetype = OpenedArchetypeType::getAny(E->getType());
auto archetype = OpenedArchetypeType::getAny(
E->getType()->getCanonicalType());
AbstractionPattern abstractionPattern(archetype);
auto &concreteTL = SGF.getTypeLowering(abstractionPattern,
concreteFormalType);
Expand Down
3 changes: 2 additions & 1 deletion lib/SILGen/SILGenType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,8 @@ static SILFunction *emitSelfConformanceWitness(SILGenModule &SGM,
ProtocolConformanceRef(conformance));

// Open the protocol type.
auto openedType = OpenedArchetypeType::get(protocol->getExistentialType());
auto openedType = OpenedArchetypeType::get(
protocol->getExistentialType()->getCanonicalType());

// Form the substitutions for calling the witness.
auto witnessSubs = SubstitutionMap::getProtocolSubstitutions(protocol,
Expand Down
5 changes: 3 additions & 2 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5370,7 +5370,8 @@ Expr *ExprRewriter::coerceSuperclass(Expr *expr, Type toType) {
if (fromInstanceType->isExistentialType()) {
// Coercion from superclass-constrained existential to its
// concrete superclass.
auto fromArchetype = OpenedArchetypeType::getAny(fromType);
auto fromArchetype = OpenedArchetypeType::getAny(
fromType->getCanonicalType());

auto *archetypeVal = cs.cacheType(new (ctx) OpaqueValueExpr(
expr->getSourceRange(), fromArchetype));
Expand Down Expand Up @@ -5433,7 +5434,7 @@ Expr *ExprRewriter::coerceExistential(Expr *expr, Type toType) {

// For existential-to-existential coercions, open the source existential.
if (fromType->isAnyExistentialType()) {
fromType = OpenedArchetypeType::getAny(fromType);
fromType = OpenedArchetypeType::getAny(fromType->getCanonicalType());

auto *archetypeVal = cs.cacheType(
new (ctx) OpaqueValueExpr(expr->getSourceRange(), fromType));
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9785,7 +9785,7 @@ ConstraintSystem::simplifyOpenedExistentialOfConstraint(
instanceTy = metaTy->getExistentialInstanceType();
}
assert(instanceTy->isExistentialType());
Type openedTy = OpenedArchetypeType::get(instanceTy);
Type openedTy = OpenedArchetypeType::get(instanceTy->getCanonicalType());
if (isMetatype)
openedTy = MetatypeType::get(openedTy, getASTContext());
return matchTypes(type1, openedTy, ConstraintKind::Bind, subflags, locator);
Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1907,7 +1907,8 @@ ConstraintSystem::getTypeOfMemberReference(
}
}
} else if (baseObjTy->isExistentialType()) {
auto openedArchetype = OpenedArchetypeType::get(baseObjTy);
auto openedArchetype = OpenedArchetypeType::get(
baseObjTy->getCanonicalType());
OpenedExistentialTypes.insert(
{getConstraintLocator(locator), openedArchetype});
baseOpenedTy = openedArchetype;
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2677,7 +2677,7 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
diagnoseInvalid(repr, attrs.getLoc(TAK_opened), diag::opened_non_protocol,
ty);
} else {
ty = OpenedArchetypeType::get(ty, attrs.OpenedID);
ty = OpenedArchetypeType::get(ty->getCanonicalType(), attrs.OpenedID);
}
attrs.clearAttribute(TAK_opened);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5511,7 +5511,7 @@ class TypeDeserializer {
existentialID,
interfaceID);

return OpenedArchetypeType::get(MF.getType(existentialID),
return OpenedArchetypeType::get(MF.getType(existentialID)->getCanonicalType(),
MF.getType(interfaceID));
}

Expand Down
31 changes: 31 additions & 0 deletions test/Constraints/sr15742.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// RUN: %target-swift-frontend -dump-ast %s | %FileCheck %s

// https://bugs.swift.org/browse/SR-15742

func fetch() {
// CHECK: open_existential_expr implicit type='Void'
// CHECK: opaque_value_expr implicit type='MyError'
// CHECK-NOT: type='SryMap<$T{{.*}}>.Failure'
sryMap { return "" }
.napError{ $0.abc() }
}

func sryMap<String>(_ transform: () -> String) -> SryMap<String> {
fatalError()
}

protocol MyError {}
extension MyError {
func abc() -> Void { }
}

protocol MyProto {
associatedtype Failure
}
extension MyProto {
func napError(_ transform: (Self.Failure) -> Void) {}
}

struct SryMap<Output> : MyProto {
typealias Failure = MyError
}
34 changes: 17 additions & 17 deletions test/SILGen/subclass_existentials.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,23 +91,23 @@ func conversions(

// Metatypes

// CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %3 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
// CHECK: [[RESULT:%.*]] = upcast [[PAYLOAD]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type to $@thick Base<Int>.Type
// CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %3 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") Base<Int> & P).Type
// CHECK: [[RESULT:%.*]] = upcast [[PAYLOAD]] : $@thick (@opened("{{.*}}") Base<Int> & P).Type to $@thick Base<Int>.Type
let _: Base<Int>.Type = baseAndPType

// CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %3 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
// CHECK: [[RESULT:%.*]] = init_existential_metatype [[PAYLOAD]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type, $@thick P.Type
// CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %3 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") Base<Int> & P).Type
// CHECK: [[RESULT:%.*]] = init_existential_metatype [[PAYLOAD]] : $@thick (@opened("{{.*}}") Base<Int> & P).Type, $@thick P.Type
let _: P.Type = baseAndPType

// CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %3 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
// CHECK: [[RESULT:%.*]] = init_existential_metatype [[PAYLOAD]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type, $@thick Q.Type
// CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %3 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") Base<Int> & P).Type
// CHECK: [[RESULT:%.*]] = init_existential_metatype [[PAYLOAD]] : $@thick (@opened("{{.*}}") Base<Int> & P).Type, $@thick Q.Type
let _: Q.Type = baseAndPType

// CHECK: [[RESULT:%.*]] = init_existential_metatype %4 : $@thick Derived.Type, $@thick (Base<Int> & P).Type
let _: (Base<Int> & P).Type = derivedType

// CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %5 : $@thick (Derived & R).Type to $@thick (@opened("{{.*}}") (Derived & R)).Type
// CHECK: [[RESULT:%.*]] = init_existential_metatype [[PAYLOAD]] : $@thick (@opened("{{.*}}") (Derived & R)).Type, $@thick (Base<Int> & P).Type
// CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %5 : $@thick (Derived & R).Type to $@thick (@opened("{{.*}}") Derived & R).Type
// CHECK: [[RESULT:%.*]] = init_existential_metatype [[PAYLOAD]] : $@thick (@opened("{{.*}}") Derived & R).Type, $@thick (Base<Int> & P).Type
let _: (Base<Int> & P).Type = derivedAndRType

// CHECK: return
Expand Down Expand Up @@ -146,23 +146,23 @@ func methodCalls(
// CHECK: dealloc_box [[RESULT_BOX]]
let _: Base<Int> & P = baseAndP.protocolSelfReturn()

// CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
// CHECK: [[METATYPE_REF:%.*]] = upcast [[METATYPE]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type to $@thick Base<Int>.Type
// CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") Base<Int> & P).Type
// CHECK: [[METATYPE_REF:%.*]] = upcast [[METATYPE]] : $@thick (@opened("{{.*}}") Base<Int> & P).Type to $@thick Base<Int>.Type
// CHECK: [[METHOD:%.*]] = function_ref @$s21subclass_existentials4BaseC15classSelfReturnACyxGXDyFZ : $@convention(method) <τ_0_0> (@thick Base<τ_0_0>.Type) -> @owned Base<τ_0_0>
// CHECK: [[RESULT_REF2:%.*]] = apply [[METHOD]]<Int>([[METATYPE_REF]])
// CHECK: [[RESULT_REF:%.*]] = unchecked_ref_cast [[RESULT_REF2]] : $Base<Int> to $@opened("{{.*}}") (Base<Int> & P)
// CHECK: [[RESULT:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") (Base<Int> & P) : $@opened("{{.*}}") (Base<Int> & P), $Base<Int> & P
// CHECK: [[RESULT_REF:%.*]] = unchecked_ref_cast [[RESULT_REF2]] : $Base<Int> to $@opened("{{.*}}") Base<Int> & P
// CHECK: [[RESULT:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") Base<Int> & P : $@opened("{{.*}}") Base<Int> & P, $Base<Int> & P
// CHECK: destroy_value [[RESULT]]
let _: Base<Int> & P = baseAndPType.classSelfReturn()

// CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
// CHECK: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") (Base<Int> & P), #P.protocolSelfReturn : <Self where Self : P> (Self.Type) -> () -> Self, [[METATYPE]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
// CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") Base<Int> & P).Type
// CHECK: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") Base<Int> & P, #P.protocolSelfReturn : <Self where Self : P> (Self.Type) -> () -> Self, [[METATYPE]] : $@thick (@opened("{{.*}}") Base<Int> & P).Type : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
// CHECK: [[RESULT_BOX:%.*]] = alloc_box
// CHECK: [[RESULT_LIFETIME:%[^,]+]] = begin_borrow [lexical] [[RESULT_BOX]]
// CHECK: [[RESULT_BUF:%.*]] = project_box
// CHECK: apply [[METHOD]]<@opened("{{.*}}") (Base<Int> & P)>([[RESULT_BUF]], [[METATYPE]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
// CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT_BUF]] : $*@opened("{{.*}}") (Base<Int> & P)
// CHECK: [[RESULT_VALUE:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") (Base<Int> & P) : $@opened("{{.*}}") (Base<Int> & P), $Base<Int> & P
// CHECK: apply [[METHOD]]<@opened("{{.*}}") Base<Int> & P>([[RESULT_BUF]], [[METATYPE]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
// CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT_BUF]] : $*@opened("{{.*}}") Base<Int> & P
// CHECK: [[RESULT_VALUE:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") Base<Int> & P : $@opened("{{.*}}") Base<Int> & P, $Base<Int> & P
// CHECK: destroy_value [[RESULT_VALUE]]
// CHECK: end_borrow [[RESULT_LIFETIME]]
// CHECK: dealloc_box [[RESULT_BOX]]
Expand Down
4 changes: 2 additions & 2 deletions test/SILOptimizer/outliner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ public func testOutlining() {
}

// CHECK-LABEL: sil @$s8outliner9dontCrash1ayyp_tF : $@convention(thin) (@in_guaranteed Any) -> () {
// CHECK: [[OBJ:%.*]] = open_existential_ref {{.*}} : $AnyObject to $@opened("{{.*}}") (AnyObject)
// CHECK: [[METH:%.*]] = objc_method [[OBJ]] : $@opened("{{.*}}") (AnyObject), #Treeish.treeishChildren!foreign : <Self where Self : Treeish> (Self) -> () -> [Any]?
// CHECK: [[OBJ:%.*]] = open_existential_ref {{.*}} : $AnyObject to $@opened("{{.*}}") AnyObject
// CHECK: [[METH:%.*]] = objc_method [[OBJ]] : $@opened("{{.*}}") AnyObject, #Treeish.treeishChildren!foreign : <Self where Self : Treeish> (Self) -> () -> [Any]?
// CHECK: [[RES:%.*]] = apply [[METH]]([[OBJ]]) : $@convention(objc_method)
// CHECK: switch_enum [[RES]]
// CHECK: } // end sil function '$s8outliner9dontCrash1ayyp_tF'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: not --crash %target-swift-frontend -emit-ir %s

func fetch() {
sryMap { return "" }
.napError{ $0.abc() }
}

func sryMap<String>(_ transform: () -> String) -> SryMap<String> {
fatalError()
}

protocol MyError {}
extension MyError {
func abc() -> Void { }
}

protocol MyProto {
associatedtype Failure
}
extension MyProto {
func napError(_ transform: (Self.Failure) -> Void) {}
}

struct SryMap<Output> : MyProto {
typealias Failure = MyError & SomeClass<Output>
}

class SomeClass<T> {}