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-1327] Ignored expressions should be correctly evaluated if they have side effects #43935

Closed
hamishknight opened this issue Apr 26, 2016 · 6 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself good first issue Good for newcomers SILGen Area → compiler: The SIL generation stage

Comments

@hamishknight
Copy link
Collaborator

Previous ID SR-1327
Radar None
Original Reporter @hamishknight
Type Bug
Status Closed
Resolution Done
Environment

Apple Swift version 4.1 (swiftlang-902.0.34 clang-902.0.30)
Target: x86_64-apple-darwin17.3.0

Additional Detail from JIRA
Votes 2
Component/s Compiler
Labels Bug, SILGen, StarterBug
Assignee @hamishknight
Priority Medium

md5: b94cb22caf1bfd698f623f19cbd8f12c

Issue Description:

The following examples should all crash at runtime, but don't:

// 1
var x: Int?
let t = type(of: x!)
print(t) // Int

// 2
struct S {
  var x: Int {
    get { fatalError() }
    set {}
  }
}

var s = S()
let kp = \S.x
let t2 = type(of: s[keyPath: kp])
print(t2) // Int

// 3
import Foundation

@objc protocol P {}
var n: P.Protocol?
var y: Protocol = n!
print(y) // <Protocol: 0x1005a98f0>

The problem is that currently with expressions like type(of:), the subexpression can be emitted as an "ignored expression" (SILGenExr.cpp, SILGenFunction::emitIgnoredExpr), meaning that for loads, we try not to actually perform the load it if we can avoid it (if loading won't have side-effects, that is).

However, currently we base the side-effects of an lvalue load off whether the components are physical or not. This is incorrect as physical components such as force unwrapping and key-paths can have side effects.

@swift-ci
Copy link
Collaborator

Comment by Jacob G (JIRA)

It also seems to only happen when using foo.bar. I would have said that this might be intentional if it also occurred when foo was defined as a constant.

@swift-ci
Copy link
Collaborator

Comment by Haris Amin (JIRA)

Can we close/resolve this issue? Running the attached `main.swift` now on 3.0.1 and 3.0.2 properly throws exception.

main.swift:11:20: error: '.dynamicType' is deprecated. Use 'type(of: ...)' instead
debugPrint(foo.bar!.dynamicType) // _dynamicType.Bar
^~~~~~~~~~~~
type(of: )
main.swift:11:19: error: value of type 'Bar' has no member 'dynamicType'
debugPrint(foo.bar!.dynamicType) // _dynamicType.Bar
~~~~~~^ ~~~~~~~~~~

@swift-ci
Copy link
Collaborator

swift-ci commented Mar 3, 2017

Comment by John Regner (JIRA)

The result you are seeing harisamin (JIRA User) is because dynamicType has been removed and replaced with the type(of: T) function.

I think the question here is "What is the expected behavior?".

In the sample code above the code intends to check/print the runtime type of a property on a struct. In my opinion, the behavior you are seeing is the correct behavior.

I've found the implementation in swift/stdlib/public/core/Builtin.swift

Looks like this is resolved by the "type checker", I'm guessing that there is no effort to "unwrap" the value that would result in the "Unexpectedly found nil" that you are expecting.

/// - Parameter value: The value to find the dynamic type of.
/// - Returns: The dynamic type, which is a value of metatype type.
@_transparent
@_semantics("typechecker.type(of:)")
public func type<T, Metatype>(of value: T) -> Metatype {
  // This implementation is never used, since calls to `Swift.type(of:)` are
  // resolved as a special case by the type checker.
  Builtin.staticReport(_trueAfterDiagnostics(), true._value,
    ("internal consistency error: 'type(of:)' operation failed to resolve"
     as StaticString).utf8Start._rawValue)
  Builtin.unreachable()
}

Suggest to close, works as expected.

@hamishknight
Copy link
Collaborator Author

john_regner (JIRA User) Although calls to type(of:) are handled as a special case by the type checker, they should still have the semantics of a function call; as the functionality is exposed to developers in the form of a function, rather than a special expression like #type(...). Therefore, the argument expression passed to it should be evaluated (and therefore crash) IMO.

@hamishknight
Copy link
Collaborator Author

The first example has actually already been fixed (accidentally, I think) by #14299, as when coercing the lvalue to an rvalue for the call argument to type(of:), the force unwrap is separated from the lvalue (i.e the lvalue x is loaded, then force unwrapped), therefore bypassing the logic in emitIgnoredExpr to avoid loading.

Though it seems a shame a load has to actually be performed here, rather than just getting the address, which is what I believe could've happened if the force unwrap component was a part of the lvalue and we fixed the side effect logic.

The side effect logic still needs fixing in the general case though.

@hamishknight
Copy link
Collaborator Author

#14410

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 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 good first issue Good for newcomers SILGen Area → compiler: The SIL generation stage
Projects
None yet
Development

No branches or pull requests

2 participants