-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Sema] SR-15940: Assert crash in TypeCheckStmt.cpp #58956
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
Conversation
@swift-ci please test |
@swift-ci please test source compatibility |
Hi @hank121314, thanks for digging into this!
As you've discovered, this bit of code calls
Notice the comment above this bit of code that you linked:
Why isn't the initializer skipped in this case based on the condition |
Hi @hborla, Thanks for the review!
For example: @propertyWrapper
public class SR_15940Bar<Value> {
public init(wrappedValue: @autoclosure () -> Value) {}
public var wrappedValue: Value {}
}
class SR_15940 {
@SR_15940Bar var a: Bool?
} The property declaration When visiting |
@hank121314 If I understand correctly |
For this test case, the initializer of // Note that we don't contextualize the initializer for a property
// with a wrapper, because the initializer will have been subsumed
// by the backing storage property. The initializer of IMHO, the fixes should be checking whether Thanks for pointing out if I have misunderstood anything! |
@hank121314 That sounds like the right approach! |
Hi @xedin ! I am trying to add a property Thanks for the review once again! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you actually need synthesized
flag since we already have isInitializerChecked(unsigned)
and based on PropertyWrapperInitializerInfoRequest::evaluate
- backing property always sets it, so really all you need to check is whether given variable is a backing property of some properly wrapper + assert that it's initializer is marked as checked and a continue;
.
Does that make sense, @hborla?
According to comments in
Thanks for pointing out if I have misunderstood anything! |
So instead of an assert it would be a check? |
If the |
If there is no initializer yet for a backing property |
Yes, In PropertyWrapperInitializerInfoRequest::evaluate, it will set initializer for a backing property and |
Sorry, you are making contradictory statements. When |
Also note that when it comes to |
But if we skip the Here is how I am trying to skip the if (!DC->isLocalContext() &&
!(PBD->getSingleVar() &&
PBD->getSingleVar()->hasAttachedPropertyWrapper())) {
auto *initContext =
cast_or_null<PatternBindingInitializer>(PBD->getInitContext(i));
if (initContext) {
// Check whether `var` is a backing storage property and its
// initializer is already checked.
bool shouldSynthesized = true;
if (auto var = PBD->getSingleVar()) {
if (auto kind =
var->getPropertyWrapperSynthesizedPropertyKind()) {
if (kind == PropertyWrapperSynthesizedPropertyKind::Backing) {
assert(PBD->isInitializerChecked(i));
shouldSynthesized = false;
}
}
}
if (shouldSynthesized) {
TypeChecker::contextualizeInitializer(initContext, init);
}
checkInitializerActorIsolation(initContext, init);
TypeChecker::checkInitializerEffects(initContext, init);
}
} And the failed test example when auto closure is not getting contextualize: // RUN: %target-swift-frontend -emit-ir %s
@propertyWrapper
public class SR_15940Bar<Value> {
private var _value: Value
public var wrappedValue: Value {
get { _value }
set {
_value = newValue
}
}
public init(wrappedValue value: @autoclosure @escaping () -> Value) {
self._value = value()
}
}
// SR-15940
class SR_15940_A {
@SR_15940Bar var a: Bool = false
} Thank you for all your assistance ❤️ ! |
Then the question is why an initializer that is marked as type-checked is not getting contextualized although it should be. |
Meaning |
If there is no explicit initializer(ex. |
The question I am asking is why isn’t explicit initializer contextualized before |
In this test case, the initializer is set as fully type-checked in TypeCheckConstraints.cpp when doing |
It seems reasonable to contextualize explicit initializers in |
This solution sounds great! |
Hi @xedin ! I have updated the PR!
For this test case: @propertyWrapper
struct SR_15940Bar {
var wrappedValue: Int { 0 }
}
struct SR_15940_B {
func a() {
@SR_15940Bar var b: Int
}
} I also notice that the flag should be turned on in case where property wrapper has defaultInit and it is a local variable. (visitingPatternBindingDecl will filter out local variables). Many thanks for the review once again! |
Thank you! I'll take a look tomorrow. |
@swift-ci please test |
@@ -2705,6 +2706,11 @@ static void typeCheckSynthesizedWrapperInitializer(VarDecl *wrappedVar, | |||
|
|||
initializer = result->getAsExpr(); | |||
|
|||
// Contextualize the initializer which is a local variable with defaultInit or | |||
// gets an independent initializer. The rest of initializer contextualizing | |||
// will be done in visitPatternBindingDecl. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After this return statement, the function also checks actor isolation and initializer effects. Do we have tests to make sure the cases where contextualize
is false
still perform actor isolation and effects checking? We might also want to call the parameter something else since it skips more than contextualizing closures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good question. @hank121314 You can comment out the logic in visitPatternBinding
and see if we get any test failures from that related to property wrappers.
Agree! Is there any recommendation about the parameter name?
There are two kinds of situations that make
Test example: @propertyWrapper
public class SR_15940Bar<Value> {
private var _value: Value
public var wrappedValue: Value {
get { _value }
set {
_value = newValue
}
}
public init(wrappedValue value: @autoclosure @escaping () -> Value) {
self._value = value()
}
}
struct SR_15940_A {
// If `dc->isLocalContext` returns `false`, actor isolation and effects checking will be perform in `visitPatternBinding`.
@SR_15940Bar var a: Bool?
func b() {
// If `dc->isLocalContext` returns `true`, actor isolation and effects checking will be perform in `TypeCheckFunctionBodyRequest`.
@SR_15940Bar var c: Bool?
}
}
Test example: @propertyWrapper
struct SR_15940Foo {
var wrappedValue: Int { 0 }
}
struct SR_15940 {
@SR_15940Foo var a: Int
} |
…performing in visitPatternBinding.
I have added a test to Concurrency/global_actor_inference.swift to make sure actor isolation and effects checking is performed in the second situation as mentioned above. Thanks for the review! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
@swift-ci please smoke test |
@swift-ci please test source compatibility |
Summary
This PR fixes: SR-15940 #58201.
In TypeCheckStorage.cpp, it will type-check default initializer and if there is a autoclosure in default initializer, its discriminator will also be set.
And In TypeCheckDeclPrimary.cpp, when visiting
PatternBindingDecl
it will type-check the autoclosure in default initializer again which might cause the assertion error.Solution
This PR tries to stop the recursive check in
TypeCheckStmt.cpp
if the autoclosure is already checked in default initializer.Thanks
Please feel free to critique, and thanks for your code review 😄 .