GSoC 2020 - Tracking for Typechecker’s Type Inference

Hello,
I'm a junior year computer science student and work on iOS app development in Swift and C++.
I would really love to contribute and work on the Swift programming language this GSoC and am particularly interested in the Tracking for Typechecker’s Type Inference project (@hborla).

This is, however, my first time working directly on a programming language/compiler and need guidance on getting started. I've gone through the contributing guidelines on the GitHub repo and Swift.org but still feel unsure about the best way to proceed.
Any help about how to work on this particular project or Swift in general would be greatly appreciated.
Thanks!

P.S. I use a MacBook and have Xcode installed (incase that involves any tips/tricks).

1 Like

Hi @yugantarjain, thank you for your interest in participating in GSoC with the Swift project!

I recommend trying to check out and build the source code for Swift. The project's readme has instructions on how to do this on various platforms, including how to build for developing on a Mac using Xcode. Please try following the steps in the readme, and let me know if you run into any issues.

Once you successfully build the Swift compiler, you'll want to start learning more about how it performs type inference. Swift's type inference algorithm is implemented as a constraint system, which is described in detail here. We have also implemented a new strategy for producing error message which is integrated directly into the constraint system, and you can learn about this strategy on the Swift Blog.

After you read a bit about the algorithm, I recommend trying to step through the source code! Try setting a breakpoint in ConstraintSystem::simplifyConstraint (in CSSimplify.cpp), compile a Swift file that contains a simple expression, and then step through the execution of the type inference algorithm. You can also use the flags -Xfrontend -debug-constraints to see the debugging output of the constraint system.

Please let me know if you have any further questions!

2 Likes

Hello Holly, thank you very much for your help!
I'm facing an issue while building the Swift project using ninja.

Build command used:
utils/build-script --release-debuginfo

There seems to be a problem in the XCTest.swift file where the imported XCTest module is not found...
File path: swift-source/swift/stdlib/public/Darwin/XCTest

I've tried to fix the issue and gain information from stack overflow etc but couldn't find anything.
I'm attaching the terminal window below along with some additional data if it may be useful.
Thanks again!

macOS version : 10.15.3
Xcode : 11.3.1
Clang : 11.0.0
Ninja : 1.10.0
CMake : 3.16.5

Please ensure that you run the update-checkout script in the repository before you run build-script. An example invocation is

$ ./utils/update-checkout --clone

Hi! Thanks a lot for your reply!

I'm building the project for the first time, so I followed the steps given in the readme in the exact manner.

Before running the build-script, I used this command -

git clone https://github.com/apple/swift.git
./swift/utils/update-checkout --clone

Does running build-script again give you a different result? If that fails, could you ensure that you have run xcode-select -s /Path/To/Xcode.app and try to rebuild?

If all else fails, nuking your build folder sometimes helps.

I will also note that working on the type checker doesn’t necessarily require you get through the entire build script, which will also try to build the overlays and a pile of extra tooling. As long as you have a standard library and a compiler built, you can still use the core workflows of your average compiler engineer.

1 Like

Running the build script is giving me the same result every time.
So, I'm trying the second option of running it after the Xcode command you mentioned.
If that also doesn't works, should I go over the whole process again?

Also, about the last piece of advice of not requiring to go through the entire build-script, how should I go about it?

Thanks

[Update]

I tried running the build script after running
sudo xcode-select -s /Applications/Xcode.app

Still getting the same error...

I would also like to add that my machine ran out of memory during the build process because of which it aborted. I made space and then re-ran the script which resumed instead of starting over. This process of making space and re-running the script happened multiple times.

I just tried out this command $ ./utils/update-checkout --clone and it failed.

======UPDATE FAILURES======

/Users/yugantarjain/swift-source/llvm-project failed (ret=1): ['git', 'rebase', 'FETCH_HEAD']

error: cannot rebase: You have unstaged changes.

error: Please commit or stash them.

update-checkout failed, fix errors and try again

The compiler build(s) requires at least 25 Gb of free disk space - I recommend double or even triple that if possible. Please ensure you have enough disk space re-run the build. It’s possible we can’t find XCTest because we ran out of disk space while writing out the modules.

To the earlier post:
One less drastic option to try is running build-script with --reconfigure to try to kick cmake’s caches. I doubt that’s going to have an impact in this case, since it seems like the script failed to build the clang module for XCTest.

For the LLVM issue, make sure you haven’t accidentally overwritten any files. You can use git reset in the directories update-checkout is complaining about.

For a per-target workflow, I wrote up some tips here. The relevant targets you need to build successfully are swift and swift-stdlib.

1 Like

Okay, that is a great post about per-target workflows, thank you very much!
I'll try to build swift and swift-stdlib and will let you know the result. Thanks again.

I've nuked the entire swift-source directory and have cloned the project from scratch. However, before I proceed with the per-target build I just wanted to make sure it is the same thing as given in the readme file of the project-

Also, here, it is being recommended to do a full build first, should I ignore that and proceed with the per-target build?

Either one works. If the full build doesn't work for you, just getting the standard library up is enough to start testing.

1 Like

Hi, in the advice given below I'm not sure about how to compile a separate swift file that would respect the breakpoint I'd set.
Should a create a new swift file in the Swift.xcodeproject itself? If yes, then what should be its target and what would be the optimal way to compile and test it?

Also, I'd just like to mention that I have used the following command for building the project and have then done an ALL_BUILD in the xcodeproject-

utils/build-script --xcode --release --debug-swift-stdlib

Thanks!

You'll want to create a separate .swift file not inside of the Swift.xcodeproj, and pass that file as an argument to the compiler. I usually have a test.swift file on my desktop and then in Xcode for Swift.xcodeproj you can go to Product > Scheme > Edit Scheme, select the "Run" tab, and then in "Arguments Passed on Launch" add a new argument with the path to your test.swift file.

2 Likes

It's also important to note that you'll have to form a full frontend command line since you'll be invoking the raw Swift compiler instead of the driver you may have been used to when building in the IDE for normal development. The frontend and driver have a non-overlapping understanding of all of the build flags, so it can be a little confusing at first to get things running.

Generally, you'll want to invoke swift passing

-frontend <action> <file>

Where <action> is a kind of FrontendOptions::ActionType. So, to typecheck (and only typecheck) a file, you want

-frontend -typecheck /path/to/test.swift

Whereas compile a file to an object file, you want

-frontend -c /path/to/test.swift -o /path/to/output.o

If you want to see what real-world frontend command lines look like, swiftc (the driver, not the frontend) inherited a driver flag from clang called -### which is an alias to -driver-print-jobs. If you take a swiftc command line and add -### to the end of it, it'll show you a list of hypothetical frontend command lines it would have run on your behalf. This even works for subtools, so today when you go to launch the Swift LLDB REPL by typing swift at the command line, you can see what's going on under the hood by invoking swift -### instead:

$ swift -###

/Applications/Xcode-beta.app/Contents/Developer/usr/bin/lldb "--repl=-enable-objc-interop -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -color-diagnostics"

You can also see the command lines that get formed for builds in the IDE by selecting the build log in the organizer. If you expand the chevron to the right of a CompileSwift command, it'll show you the full frontend command line invoked to build that file/module. You can even tell the IDE to use a swiftc you built by setting the SWIFT_EXEC build setting to point to your swiftc. The command lines generated in the IDE from that custom compiler can be copied and pasted straight into the command line arguments field in Xcode for your compiler so you can debug a live build.

2 Likes

Hi @hborla @codafi, thank you very much for your quick help and detailed replies!
I was able to successfully go through the process, however, it seems like the breakpoint isn't making any difference in the debugger console (ConstraintSystem::simplifyConstraint is being called for sure) (and Debug Executable is checked).

I'd also like to ask a few doubts regarding the proposal in respect to the expected outcomes given in official ideas list-

  1. Deliver an interactive command-line tool for visualizing the source of type inference. This will be a separate command-line tool that reads in the detailed type inference information and allows the user to query the source of type inference for a particular type in the solution.

Does this means that the command-line tool will take the debugger output as input and produce an easy to understand visualisation/comprehension of that same data as output?

  1. Implement tracking of constraints that caused the solver to infer a type, along with a compiler flag for writing the solution with detailed type inference sources to a file.

Is this a part of the method/process to achieve the end result (the command line tool output) or is it something else?

  1. Also...being a first-time contributor to the Swift project or any compiler, I'm wondering if working on Type Inference would be too overwhelming for me? I've gone through the Swift docs for this and some additional material too, but I thought I'd ask.

Thank you

It seems like the breakpoint isn't making any difference in the debugger console

What compiler flags are you using? Try -Xfrontend -debug-constraints

Does this means that the command-line tool will take the debugger output as input and produce an easy to understand visualisation/comprehension of that same data as output?

You will need to add a new form of output to the compiler, which will be the source constraint for each type variable binding. The separate command line tool will take this new compiler output as input in order to provide a visualization of the type variable binding sequence for a particular expression in the source code.

Is [implement tracking of constraints] a part of the method/process to achieve the end result (the command line tool output) or is it something else?

Yes, implementing tracking of constraints that caused the solver to infer a type is part of the process to achieve the end result. Currently, the compiler does not record or output the source constraints for bindings that it attempts.

Being a first-time contributor to the Swift project or any compiler, I'm wondering if working on Type Inference would be too overwhelming for me?

Don't worry that you haven't contributed to Swift before! I didn't contribute to Swift or any other compiler before I started working on Swift. If you are able to write a proposal for the type inference project that demonstrates your understanding of the topic and the project requirements, then I think you can successfully complete the project in the given time frame.

1 Like

Thank you very much! I'll try to submit a proposal draft by today itself.

Regarding the breakpoint problem-

  • Yes, I've used the compiler flags that you suggested. In "arguments passed on launch" I've used them in the following way:
    -Xfrontend -debug-constraints /path/to/test.swift
  • I tried to search and fix it myself, and realised that in the scheme editor "debug executable' must be checked. In my case, it was already checked.
  • Using printf, I've confirmed that simplifyConstraint is definitely being called (multiple times in fact).
  • Lastly, I tried using breakpoints in another xcodeproject, and it is working fine in them.