{"id":19212517,"url":"https://github.com/fasterthanlime/rustc-superlinear-sadness","last_synced_at":"2025-10-26T05:48:34.799Z","repository":{"id":44926691,"uuid":"513136608","full_name":"fasterthanlime/rustc-superlinear-sadness","owner":"fasterthanlime","description":"Trying to reproduce build time issues with tower","archived":false,"fork":false,"pushed_at":"2022-07-12T18:24:26.000Z","size":31,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-12T20:49:56.319Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fasterthanlime.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-07-12T12:39:11.000Z","updated_at":"2022-07-13T01:55:23.000Z","dependencies_parsed_at":"2022-09-19T17:30:19.702Z","dependency_job_id":null,"html_url":"https://github.com/fasterthanlime/rustc-superlinear-sadness","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fasterthanlime/rustc-superlinear-sadness","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fasterthanlime%2Frustc-superlinear-sadness","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fasterthanlime%2Frustc-superlinear-sadness/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fasterthanlime%2Frustc-superlinear-sadness/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fasterthanlime%2Frustc-superlinear-sadness/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fasterthanlime","download_url":"https://codeload.github.com/fasterthanlime/rustc-superlinear-sadness/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fasterthanlime%2Frustc-superlinear-sadness/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268177897,"owners_count":24208397,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-01T02:00:08.611Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T13:47:13.631Z","updated_at":"2025-10-26T05:48:29.758Z","avatar_url":"https://github.com/fasterthanlime.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rustc-superlinear-sadness\n\nShowcase of how tower-style code can make compile times explode on rustc\nnightly as of 2022-07-12.\n\n## Timeline\n\n  * 2022-07-12: repro created, profiling work by @fasterthanlime, @eddyb \u0026 @BoxyUwU to scope down the problem\n  * 2022-07-12: [rustc issue 99188](https://github.com/rust-lang/rust/issues/99188) opened by @eddyb\n\n## Repo structure\n\nAll the code is in `src/main.rs`, it has no dependencies - it doesn't even\nimport anything outside the rust 2021 prelude.\n\nThe code will only compile if one of those `cfg` is set:\n\n  * `assoc_type_0`, `assoc_type_1`, `assoc_type_2`, `assoc_type_3`\n  * `outlives`\n  * `clone`\n\nYou can \"add nesting\" to show how compile time evolves, by adding `--cfg more1`,\n`--cfg more2`, etc. until `more7`.\n\n## Justfile / commands\n\n`just run --cfg assoc_type_0` will run `rustc`, using the `stage1` toolchain,\nenabling self-profiling.\n\nFor the rest of the commands to work, you'll need a fork of rustc that records\n`SelectionContext::evaluate_predicate_recursively` using the self-profiler.\nYou can use [this branch of my fork](https://github.com/fasterthanlime/rust/tree/self-profile-evaluate-predicate-recursively). If you don't, you'll still notice\ncompile times going up but you won't get a nice \"leaderboard\" like in the README\nexamples. \n\n`crox` is being run on the most recent `*.mm_profdata` file to generate a\n\"chrome tracing\" file (as `chrome_profiler.json`), and then `jq` is used to\nfilter only the `evaluate_predicate_recursively` calls, which are then\nsorted.\n\n`just seq {name}` will run `just run` multiple times in a row, with a higher\n`moreN` value every time, showing compile time growth. This is what is showcased\nin the README.\n\n## assoc types\n\nWith zero associated types being constrained, even with nested\n`MiddleService\u003cMiddleService\u003c...\u003e\u003e` types, the number of checks is constant:\n\n```rust\nimpl\u003c'a, S\u003e Service\u003c\u0026'a ()\u003e for MiddleService\u003cS\u003e\nwhere\n    for\u003c'b\u003e S: Service\u003c\u0026'b ()\u003e,\n```\n\n```shell\n$ just seq assoc_type_0\n      6 Obligation(predicate=Binder(TraitPredicate(\u003c() as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n      6 Obligation(predicate=Binder(TraitPredicate(\u003c() as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n      6 Obligation(predicate=Binder(TraitPredicate(\u003c() as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n      6 Obligation(predicate=Binder(TraitPredicate(\u003c() as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n      6 Obligation(predicate=Binder(TraitPredicate(\u003c() as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n      6 Obligation(predicate=Binder(TraitPredicate(\u003c() as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n      6 Obligation(predicate=Binder(TraitPredicate(\u003c() as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n```\n\n\u003cimg width=\"484\" alt=\"image\" src=\"https://user-images.githubusercontent.com/7998310/178554485-44b1b591-2ab7-4d9a-914d-57e663c275bb.png\"\u003e\n\nWith one associated type being constrained, it's linear:\n\n```rust\n#[cfg(assoc_type_1)]\nimpl\u003c'a, S\u003e Service\u003c\u0026'a ()\u003e for MiddleService\u003cS\u003e\nwhere\n    for\u003c'b\u003e S: Service\u003c\u0026'b (), Response = ()\u003e,\n```\n\n```shell\n$ just seq assoc_type_1\n     19 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n     23 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n     27 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n     31 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n     35 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n     39 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n     43 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n```\n\n\u003cimg width=\"485\" alt=\"image\" src=\"https://user-images.githubusercontent.com/7998310/178554499-b71dcc45-6e8f-44de-859e-8e305af7075b.png\"\u003e\n\nWith two, it's exponential ($2^x$ growth):\n\n```rust\n#[cfg(assoc_type_2)]\nimpl\u003c'a, S\u003e Service\u003c\u0026'a ()\u003e for MiddleService\u003cS\u003e\nwhere\n    for\u003c'b\u003e S: Service\u003c\u0026'b (), Response = (), Error = ()\u003e,\n```\n\n```shell\n$ just seq assoc_type_2\n    108 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n    220 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n    444 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n    892 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n   1788 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n   3580 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n   7164 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n```\n\n\u003cimg width=\"492\" alt=\"image\" src=\"https://user-images.githubusercontent.com/7998310/178554515-7ff922b3-b752-49fc-afff-0f63bf7b77e3.png\"\u003e\n\nWith three, it's exponential, but worse ($3^x$ growth)\n\n```rust\nimpl\u003c'a, S\u003e Service\u003c\u0026'a ()\u003e for MiddleService\u003cS\u003e\nwhere\n    for\u003c'b\u003e S: Service\u003c\u0026'b (), Response = (), Error = (), ThirdType = ()\u003e,\n```\n\n```shell\n$ just seq assoc_type_3\n    403 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n   1213 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n   3643 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n  10933 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n  32803 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n  98413 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n 295243 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n```\n\n\u003cimg width=\"489\" alt=\"image\" src=\"https://user-images.githubusercontent.com/7998310/178554540-3563073b-d5f7-4766-a792-e65015e2836d.png\"\u003e\n\n## outlives constraint\n\nThis type of constraint also shows exponential behavior ($2^x$):\n\n```rust\nimpl\u003c'a, S\u003e Service\u003c\u0026'a ()\u003e for MiddleService\u003cS\u003e\nwhere\n    for\u003c'b\u003e S: Service\u003c\u0026'b ()\u003e,\n    for\u003c'b\u003e \u003cS as Service\u003c\u0026'b ()\u003e\u003e::Future: 'b,\n```\n\n```shell\n$ just seq outlives\n     26 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n     50 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n     98 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n    194 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n    386 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n    770 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n   1538 Obligation(predicate=Binder(TraitPredicate(\u003cInnerService as std::marker::Sized\u003e, polarity:Positive), []), depth=?)\n```\n\n\u003cimg width=\"493\" alt=\"image\" src=\"https://user-images.githubusercontent.com/7998310/178555618-924ca4fb-f69d-41fb-afd6-fe0f0d8f5913.png\"\u003e\n\nAnd a `Clone` constraint shows the exact same thing (numbers not shown here):\n\n```rust\nimpl\u003c'a, S\u003e Service\u003c\u0026'a ()\u003e for MiddleService\u003cS\u003e\nwhere\n    for\u003c'b\u003e S: Service\u003c\u0026'b ()\u003e,\n    for\u003c'b\u003e \u003cS as Service\u003c\u0026'b ()\u003e\u003e::Future: Clone,\n```\n\n## smaller repro\n\nHere's a smaller repro of the \"assoc types\" explosion: [Playground](https://play.rust-lang.org/?version=stable\u0026mode=debug\u0026edition=2021\u0026gist=e63793ea5031cb7aa38c64a71e49de23).\n\nAdding another `\u0026` in `main` makes the playground time out (be nice to the playground).\n\n## next steps\n\nSeveral issues are being filed, let's see where this goes!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffasterthanlime%2Frustc-superlinear-sadness","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffasterthanlime%2Frustc-superlinear-sadness","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffasterthanlime%2Frustc-superlinear-sadness/lists"}