Skip to content
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

[Sema] Fix a couple of property override crashers #30792

Merged
merged 2 commits into from Apr 3, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 38 additions & 9 deletions lib/Sema/CodeSynthesis.cpp
Expand Up @@ -41,20 +41,49 @@ const bool IsImplicit = true;

Expr *swift::buildSelfReference(VarDecl *selfDecl,
SelfAccessorKind selfAccessorKind,
bool isLValue,
ASTContext &ctx) {
bool isLValue, Type convertTy) {
auto &ctx = selfDecl->getASTContext();
auto selfTy = selfDecl->getType();

switch (selfAccessorKind) {
case SelfAccessorKind::Peer:
assert(!convertTy || convertTy->isEqual(selfTy));
return new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), IsImplicit,
AccessSemantics::Ordinary,
isLValue
? LValueType::get(selfDecl->getType())
: selfDecl->getType());
isLValue ? LValueType::get(selfTy) : selfTy);

case SelfAccessorKind::Super:
case SelfAccessorKind::Super: {
assert(!isLValue);
return new (ctx) SuperRefExpr(selfDecl, SourceLoc(), IsImplicit,
selfDecl->getType()->getSuperclass());

// Get the superclass type of self, looking through a metatype if needed.
auto isMetatype = false;
if (auto *metaTy = selfTy->getAs<MetatypeType>()) {
isMetatype = true;
selfTy = metaTy->getInstanceType();
}
selfTy = selfTy->getSuperclass();
if (isMetatype)
selfTy = MetatypeType::get(selfTy);

auto *superRef =
new (ctx) SuperRefExpr(selfDecl, SourceLoc(), IsImplicit, selfTy);

// If no conversion type was specified, or we're already at that type, we're
// done.
if (!convertTy || convertTy->isEqual(selfTy))
return superRef;

// Insert the appropriate expr to handle the upcast.
if (isMetatype) {
assert(convertTy->castTo<MetatypeType>()
->getInstanceType()
->isExactSuperclassOf(selfTy->getMetatypeInstanceType()));
return new (ctx) MetatypeConversionExpr(superRef, convertTy);
} else {
assert(convertTy->isExactSuperclassOf(selfTy));
return new (ctx) DerivedToBaseExpr(superRef, convertTy);
}
}
}
llvm_unreachable("bad self access kind");
}
Expand Down Expand Up @@ -537,7 +566,7 @@ synthesizeDesignatedInitOverride(AbstractFunctionDecl *fn, void *context) {
// Reference to super.init.
auto *selfDecl = ctor->getImplicitSelfDecl();
auto *superRef = buildSelfReference(selfDecl, SelfAccessorKind::Super,
/*isLValue=*/false, ctx);
/*isLValue=*/false);

SubstitutionMap subs;
if (auto *genericEnv = fn->getGenericEnvironment())
Expand Down
13 changes: 9 additions & 4 deletions lib/Sema/CodeSynthesis.h
Expand Up @@ -50,10 +50,15 @@ enum class SelfAccessorKind {
Super,
};

Expr *buildSelfReference(VarDecl *selfDecl,
SelfAccessorKind selfAccessorKind,
bool isLValue,
ASTContext &ctx);
/// Builds a reference to the \c self decl in a function.
///
/// \param selfDecl The self decl to reference.
/// \param selfAccessorKind The kind of access being performed.
/// \param isLValue Whether the resulting expression is an lvalue.
/// \param convertTy The type of the resulting expression. For a reference to
/// super, this can be a superclass type to upcast to.
Expr *buildSelfReference(VarDecl *selfDecl, SelfAccessorKind selfAccessorKind,
bool isLValue, Type convertTy = Type());

/// Build an expression that evaluates the specified parameter list as a tuple
/// or paren expr, suitable for use in an apply expr.
Expand Down
32 changes: 19 additions & 13 deletions lib/Sema/TypeCheckStorage.cpp
Expand Up @@ -654,6 +654,13 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
semantics = AccessSemantics::Ordinary;
selfAccessKind = SelfAccessorKind::Super;

auto isMetatype = false;
if (auto *metaTy = selfTypeForAccess->getAs<MetatypeType>()) {
isMetatype = true;
selfTypeForAccess = metaTy->getInstanceType();
}

// Adjust the self type of the access to refer to the relevant superclass.
auto *baseClass = override->getDeclContext()->getSelfClassDecl();
selfTypeForAccess = selfTypeForAccess->getSuperclassForDecl(baseClass);
subs =
Expand All @@ -663,6 +670,9 @@ static Expr *buildStorageReference(AccessorDecl *accessor,

storage = override;

if (isMetatype)
selfTypeForAccess = MetatypeType::get(selfTypeForAccess);

// Otherwise do a self-reference, which is dynamically bogus but
// should be statically valid. This should only happen in invalid cases.
} else {
Expand Down Expand Up @@ -751,6 +761,11 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
bool isMemberLValue = isLValue;
auto propertyWrapperMutability =
[&](Decl *decl) -> Optional<std::pair<bool, bool>> {
// If we're not accessing via a property wrapper, we don't need to adjust
// the mutability.
if (target != TargetImpl::Wrapper && target != TargetImpl::WrapperStorage)
return None;

auto var = dyn_cast<VarDecl>(decl);
if (!var)
return None;
Expand Down Expand Up @@ -781,17 +796,8 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
isSelfLValue |= mut->second;
}

Expr *selfDRE =
buildSelfReference(selfDecl, selfAccessKind, isSelfLValue,
ctx);
if (isSelfLValue)
selfTypeForAccess = LValueType::get(selfTypeForAccess);

if (!selfDRE->getType()->isEqual(selfTypeForAccess)) {
assert(selfAccessKind == SelfAccessorKind::Super);
selfDRE = new (ctx) DerivedToBaseExpr(selfDRE, selfTypeForAccess);
}

Expr *selfDRE = buildSelfReference(selfDecl, selfAccessKind, isSelfLValue,
/*convertTy*/ selfTypeForAccess);
Expr *lookupExpr;
ConcreteDeclRef memberRef(storage, subs);
auto type = storage->getValueInterfaceType().subst(subs);
Expand Down Expand Up @@ -1452,8 +1458,8 @@ synthesizeObservedSetterBody(AccessorDecl *Set, TargetImpl target,
ValueDRE->setType(arg->getType());

if (SelfDecl) {
auto *SelfDRE = buildSelfReference(SelfDecl, SelfAccessorKind::Peer,
IsSelfLValue, Ctx);
auto *SelfDRE =
buildSelfReference(SelfDecl, SelfAccessorKind::Peer, IsSelfLValue);
SelfDRE = maybeWrapInOutExpr(SelfDRE, Ctx);
auto *DSCE = new (Ctx) DotSyntaxCallExpr(Callee, SourceLoc(), SelfDRE);

Expand Down
34 changes: 34 additions & 0 deletions test/SILGen/accessors.swift
Expand Up @@ -133,6 +133,40 @@ func test_rec2(_ outer: inout Rec2Outer) -> Int {
// CHECK: sil hidden [ossa] @$s9accessors9test_rec2ySiAA9Rec2OuterVzF : $@convention(thin) (@inout Rec2Outer) -> Int {
// CHECK: function_ref @$s9accessors9Rec2OuterV5innerAA0B5InnerVvau : $@convention(method) (@inout Rec2Outer) -> UnsafeMutablePointer<Rec2Inner>

// SR-12456: Compiler crash on class var override adding observer.
class SR12456Base {
open class var instance: SR12456Base {
get {
return SR12456Base()
}
set {}
}
}

class SR12456Subclass : SR12456Base {
override class var instance: SR12456Base {
didSet {}
}
}

// Make sure we can handle more complicated overrides.
class Parent<V> {
class C<T, U> {
class var foo: Int { get { 0 } set {} }
}
class D<T> : C<T, Int> {}
class E : D<Double> {
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s9accessors6ParentC1EC3fooSivgZ : $@convention(method) <V> (@thick Parent<V>.E.Type) -> Int
// CHECK: [[TY:%.+]] = upcast {{%.+}} : $@thick Parent<V>.E.Type to $@thick Parent<V>.D<Double>.Type
// CHECK: [[UPCASTTY:%.+]] = upcast [[TY]] : $@thick Parent<V>.D<Double>.Type to $@thick Parent<V>.C<Double, Int>.Type
// CHECK: [[GETTER:%.+]] = function_ref @$s9accessors6ParentC1CC3fooSivgZ : $@convention(method) <τ_0_0><τ_1_0, τ_1_1> (@thick Parent<τ_0_0>.C<τ_1_0, τ_1_1>.Type) -> Int
// CHECK: apply [[GETTER]]<V, Double, Int>([[UPCASTTY]])
override class var foo: Int {
didSet {}
}
}
}

struct Foo {
private subscript(privateSubscript x: Void) -> Void {
// CHECK-DAG: sil private [ossa] @$s9accessors3FooV16privateSubscriptyyt_tc33_D7F31B09EE737C687DC580B2014D759CLlig : $@convention(method) (Foo) -> () {
Expand Down
28 changes: 28 additions & 0 deletions test/SILGen/property_wrappers.swift
Expand Up @@ -653,6 +653,34 @@ struct ObservedObject<ObjectType : AnyObject > {
}
}

// SR-12443: Crash on property with wrapper override that adds observer.
@propertyWrapper
struct BasicIntWrapper {
var wrappedValue: Int
}

class Someclass {
@BasicIntWrapper var property: Int = 0
}

class Somesubclass : Someclass {
override var property: Int {
// Make sure we don't interact with the property wrapper, we just delegate
// to the superclass' accessors.
// CHECK-LABEL: sil hidden [ossa] @$s17property_wrappers12SomesubclassC0A0Sivs : $@convention(method) (Int, @guaranteed Somesubclass) -> ()
// CHECK: bb0([[NEW:%.+]] : $Int, {{%.+}} : @guaranteed $Somesubclass):
// CHECK: [[GETTER:%.+]] = function_ref @$s17property_wrappers9SomeclassC0A0Sivg : $@convention(method) (@guaranteed Someclass) -> Int
// CHECK: [[OLD:%.+]] = apply [[GETTER]]({{%.+}}) : $@convention(method) (@guaranteed Someclass) -> Int
// CHECK: [[SETTER:%.+]] = function_ref @$s17property_wrappers9SomeclassC0A0Sivs : $@convention(method) (Int, @guaranteed Someclass) -> ()
// CHECK: apply [[SETTER]]([[NEW]], {{%.+}}) : $@convention(method) (Int, @guaranteed Someclass) -> ()
// CHECK: [[DIDSET:%.+]] = function_ref @$s17property_wrappers12SomesubclassC0A0SivW : $@convention(method) (Int, @guaranteed Somesubclass) -> ()
// CHECK: apply [[DIDSET]]([[OLD]], {{%.+}}) : $@convention(method) (Int, @guaranteed Somesubclass) -> ()
didSet {
print("Subclass")
}
}
}

// rdar://problem/58986940 - composition of wrappers with autoclosure
@propertyWrapper
struct Once<Value> {
Expand Down