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

[SR-488] Crash when emitting store into a generic member, from initializer in an extension #43105

Closed
jadengeller mannequin opened this issue Jan 7, 2016 · 11 comments
Closed
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software

Comments

@jadengeller
Copy link
Mannequin

jadengeller mannequin commented Jan 7, 2016

Previous ID SR-488
Radar rdar://problem/21473547
Original Reporter @JadenGeller
Type Bug
Status Resolved
Resolution Done

Attachment: Download

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, CompilerCrash
Assignee @slavapestov
Priority Medium

md5: 4cc3ecb039495bae0b76cbb3c7e41251

is duplicated by:

  • SR-493 Compiler crashes when Implementing ArrayLitteralConvertible In a generic struct

relates to:

  • SR-493 Compiler crashes when Implementing ArrayLitteralConvertible In a generic struct

Issue Description:

When a generic type Blah<Value> contains a generic property with a default value, such as var backing: Value? = nil, the compiler will crash if an initializer is placed in an extension (even in the same file).

struct Blah<Value> {
    var backing: Value?
}

extension Blah {
    init(test: Int) {
        // crash when emitting implicit store "backing = nil"
    }
}

The stack trace is:

#&#8203;4  llvm_unreachable("unexpected storage type that differs from type-of-rvalue");
#&#8203;5  emitStoreOfSemanticRValue(swift::Lowering::SILGenFunction&, swift::SILLocation, swift::SILValue, swift::SILValue, swift::Lowering::TypeLowering const&, swift::IsInitialization_t)
#&#8203;6  swift::Lowering::SILGenFunction::emitSemanticStore(swift::SILLocation, swift::SILValue, swift::SILValue, swift::Lowering::TypeLowering const&, swift::IsInitialization_t)
#&#8203;7  swift::Lowering::ManagedValue::assignInto(swift::Lowering::SILGenFunction&, swift::SILLocation, swift::SILValue)
#&#8203;8  assignRecursive(swift::Lowering::SILGenFunction&, swift::SILLocation, swift::CanType, llvm::ArrayRef<swift::Lowering::ManagedValue>&, swift::SILValue)
#&#8203;9  swift::Lowering::RValue::assignInto(swift::Lowering::SILGenFunction&, swift::SILLocation, swift::SILValue) &&
#&#8203;10 swift::Lowering::SILGenFunction::emitAssignToLValue(swift::SILLocation, swift::Lowering::RValue&&, swift::Lowering::LValue&&)
#&#8203;11 emitMemberInit(swift::Lowering::SILGenFunction&, swift::VarDecl*, swift::Pattern*, swift::Lowering::RValue&&)
#&#8203;12 emitMemberInit(swift::Lowering::SILGenFunction&, swift::VarDecl*, swift::Pattern*, swift::Lowering::RValue&&)
#&#8203;13 swift::Lowering::SILGenFunction::emitMemberInitializers(swift::VarDecl*, swift::NominalTypeDecl*)
#&#8203;14 swift::Lowering::SILGenFunction::emitValueConstructor(swift::ConstructorDecl*)
#&#8203;15 swift::Lowering::SILGenModule::emitConstructor(swift::ConstructorDecl*)::$_4::operator()(swift::SILFunction*) const
#&#8203;16 void emitOrDelayFunction<swift::Lowering::SILGenModule::emitConstructor(swift::ConstructorDecl*)::$_4>(swift::Lowering::SILGenModule&, swift::SILDeclRef, swift::Lowering::SILGenModule::emitConstructor(swift::ConstructorDecl*)::$_4&&)
#&#8203;17 swift::Lowering::SILGenModule::emitConstructor(swift::ConstructorDecl*)
#&#8203;18 SILGenExtension::visitConstructorDecl(swift::ConstructorDecl*)
@jtbandes
Copy link
Collaborator

I think the issue arises from the condition if (rvalue->getType() == destTL.getLoweredType()) inside SILGenFunction::emitSemanticStore(). When the member (destination) in question is of a generic parameter type, this returns false, even though the types "should" be the same (I think—because their getString() returns the same string, such as $*Optional<Value>).

@jtbandes
Copy link
Collaborator

cc @slavapestov who might have some chance at fixing this. I think checkExtensionGenericParams may need to be modified so that the extension uses the same archetype(s) as its extended type, but I'm not sure how to do that.

@slavapestov
Copy link
Member

Extensions have different archetypes than the extended type. I think the problem is that the archetype from the context of the type should not be showing up in the SIL at all. I'll take a look.

@slavapestov
Copy link
Member

We cannot just re-use original archetypes in the extension, because it might have a different set of generic parameters, eg 'extension SomeClass where T.AssocType == Int'.

@slavapestov
Copy link
Member

The pattern initializer expression is always written in terms of the original archetypes, and SILGen just blindly emits it into the constructor, even if the constructor is in a different context.

@slavapestov
Copy link
Member

What we need to do is emit each initializer into its own SIL function, with a new kind of SILDeclRef to refer to pattern initializer functions. Extension initializers will then call these functions instead of directly emitting the expression in the initializer.

This function will have a generic signature and interface type, and re-use the original archetypes from the containing declaration. When called from an extension, the right substitutions will be used.

@jtbandes
Copy link
Collaborator

jtbandes commented Jun 2, 2016

My knowledge of this is limited, but shouldn't the extension have awareness of the extended type's archetypes too? Shouldn't it be possible to simply enumerate the members that are being initialized, and emit the initializers with correct knowledge of the type of the member (which, as you said, may be less constrained than the extension's own archetypes)?

@slavapestov
Copy link
Member

Joe also mentioned there's an orthogonal issue – we need Sema diagnostics to ban extensions from adding designated initializers outright, if any of these are true:

  • if the extension is in a different file than the original type and the original type has private members

  • if the extension is in a different module than the original type and the original type has internal members

  • if the extension is in a different module than the original type is resilient

@slavapestov
Copy link
Member

Archetypes are specific to a given scope (more precisely, a DeclContext). a SILFunction's body can only use archetypes from that context, because SIL and IRGen rely extensively on the pointer identity of archetypes making sense.

The problem is that initializers are arbitrary Exprs, so unless we rework all of SILGen to remap types arbitrarily, it won't work in the general case.

Putting initializers in their own function makes sense for other reasons too. We've had bugs in the past with closures and such crashing in initializer expressions because of bits of SILGen not being set up to emit Exprs more than once.

Emitting the initializer expression once in its own function associated with the original type is the sanest fix.

@slavapestov
Copy link
Member

An analogous situation exists with default argument initializers – take a look at how we emit those, and how they're handled in type lowering and SILDeclRefs, etc.

Jacob, if you wanted to take this on, I'd be happy to help in any way I can! 🙂

@slavapestov
Copy link
Member

Fixed in #3949

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added the crash Bug: A crash, i.e., an abnormal termination of software label Dec 12, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software
Projects
None yet
Development

No branches or pull requests

3 participants