-
Notifications
You must be signed in to change notification settings - Fork 10.5k
DefiniteInitialization: correctly handle implicit closures. #35276
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// RUN: %target-sil-opt -enable-sil-verify-all %s -definite-init | ||
|
||
// Test that implicit closures don't count as use of the whole self and only | ||
// actual uses inside the closures are taken into account. | ||
|
||
// Check that no errors are generated. No FileCheck needed. | ||
|
||
sil_stage raw | ||
|
||
import Builtin | ||
import Swift | ||
import SwiftShims | ||
|
||
struct SimpleStruct { | ||
@_hasStorage let x: Bool | ||
@_hasStorage let y: Bool | ||
init() | ||
} | ||
|
||
class SimpleClass { | ||
@_hasStorage final let x: Bool | ||
@_hasStorage final let y: Bool | ||
init() | ||
} | ||
|
||
sil [ossa] @$s4test1SVACycfC : $@convention(method) (Bool) -> SimpleStruct { | ||
bb0(%0 : $Bool): | ||
%1 = alloc_stack $SimpleStruct, var, name "self" | ||
%2 = mark_uninitialized [rootself] %1 : $*SimpleStruct | ||
%7 = begin_access [modify] [static] %2 : $*SimpleStruct | ||
%8 = struct_element_addr %7 : $*SimpleStruct, #SimpleStruct.x | ||
assign %0 to %8 : $*Bool | ||
end_access %7 : $*SimpleStruct | ||
%16 = function_ref @implicit_closure_struct : $@convention(thin) (@inout_aliasable SimpleStruct) -> (Bool, @error Error) | ||
%17 = partial_apply [callee_guaranteed] %16(%2) : $@convention(thin) (@inout_aliasable SimpleStruct) -> (Bool, @error Error) | ||
destroy_value %17 : $@callee_guaranteed () -> (Bool, @error Error) | ||
%23 = begin_access [modify] [static] %2 : $*SimpleStruct | ||
%24 = struct_element_addr %23 : $*SimpleStruct, #SimpleStruct.y | ||
assign %0 to %24 : $*Bool | ||
end_access %23 : $*SimpleStruct | ||
%27 = load [trivial] %2 : $*SimpleStruct | ||
dealloc_stack %1 : $*SimpleStruct | ||
return %27 : $SimpleStruct | ||
} | ||
|
||
sil private [transparent] [ossa] @implicit_closure_struct : $@convention(thin) (@inout_aliasable SimpleStruct) -> (Bool, @error Error) { | ||
bb0(%0 : $*SimpleStruct): | ||
debug_value_addr %0 : $*SimpleStruct, var, name "self", argno 2 | ||
%3 = begin_access [read] [static] %0 : $*SimpleStruct | ||
%4 = struct_element_addr %3 : $*SimpleStruct, #SimpleStruct.x | ||
%5 = load [trivial] %4 : $*Bool | ||
end_access %3 : $*SimpleStruct | ||
return %5 : $Bool | ||
} | ||
|
||
sil [ossa] @$s4test11SimpleClassC1bACSb_tcfc : $@convention(method) (Bool, @owned SimpleClass) -> @owned SimpleClass { | ||
bb0(%0 : $Bool, %1 : @owned $SimpleClass): | ||
%4 = mark_uninitialized [rootself] %1 : $SimpleClass | ||
%5 = begin_borrow %4 : $SimpleClass | ||
%6 = ref_element_addr %5 : $SimpleClass, #SimpleClass.x | ||
assign %0 to %6 : $*Bool | ||
end_borrow %5 : $SimpleClass | ||
%9 = begin_borrow %4 : $SimpleClass | ||
%11 = function_ref @implicit_closure_class : $@convention(thin) (@guaranteed SimpleClass) -> (Bool, @error Error) | ||
%12 = copy_value %4 : $SimpleClass | ||
%13 = partial_apply [callee_guaranteed] %11(%12) : $@convention(thin) (@guaranteed SimpleClass) -> (Bool, @error Error) | ||
destroy_value %13 : $@callee_guaranteed () -> (Bool, @error Error) | ||
%19 = ref_element_addr %9 : $SimpleClass, #SimpleClass.y | ||
assign %0 to %19 : $*Bool | ||
end_borrow %9 : $SimpleClass | ||
return %4 : $SimpleClass | ||
} | ||
|
||
sil private [transparent] [ossa] @implicit_closure_class : $@convention(thin) (@guaranteed SimpleClass) -> (Bool, @error Error) { | ||
bb0(%0 : @guaranteed $SimpleClass): | ||
debug_value %0 : $SimpleClass, let, name "self", argno 2 | ||
%3 = ref_element_addr %0 : $SimpleClass, #SimpleClass.x | ||
%4 = load [trivial] %3 : $*Bool | ||
return %4 : $Bool | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// RUN: %target-swift-frontend -emit-sil %s -o /dev/null | ||
|
||
// Test boolean operators with implicit closures | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I need a sil test case before I can approve this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added one. |
||
|
||
struct Simple { | ||
let x: Bool | ||
let y: Bool | ||
|
||
init() { | ||
x = false | ||
y = false || x | ||
} | ||
} | ||
|
||
struct NestedClosures { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a test for a generic struct or a struct with an existential field to test the address only case There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
let x: Bool | ||
let y: Bool | ||
let z: Bool | ||
|
||
init(a: Bool) { | ||
x = false | ||
y = false | ||
z = false || (y || (x || a)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does your code behave the same with explicit "self." qualification too? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes. I added a test |
||
} | ||
|
||
init(b: Bool) { | ||
x = false | ||
y = false | ||
// With explicit self | ||
z = false || (self.y || (self.x || b)) | ||
} | ||
} | ||
|
||
class SimpleClass { | ||
let x: Bool | ||
let y: Bool | ||
|
||
init() { | ||
x = false | ||
y = false || x | ||
} | ||
} | ||
|
||
func forward(_ b: inout Bool) -> Bool { | ||
return b | ||
} | ||
|
||
struct InoutUse { | ||
var x: Bool | ||
var y: Bool | ||
|
||
init() { | ||
x = false | ||
y = false || forward(&x) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add some invalid test cases as well, to ensure we still diagnose when the field is not initialized? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another case to test is partial initialization:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The invalid test cases are in |
||
} | ||
} | ||
|
||
protocol P { | ||
var b: Bool { get } | ||
} | ||
|
||
struct Generic<T : P> { | ||
let x: T | ||
let y: Bool | ||
|
||
init(_ t: T) { | ||
x = t | ||
y = false || x.b | ||
} | ||
} | ||
|
||
|
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.
What if TheMemory.getType() is an address-only type because 'self' has an address-only field?
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.
TheMemory
is always an object type. I added an assertThere 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.
Should it be a CanType instead of a SILType then, if the address/object bit is not used?
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.
maybe