commit
59d3572bd6
375 changed files with 4611 additions and 1511 deletions
|
|
@ -8,3 +8,5 @@ a06baa56b95674fc626b3c3fd680d6a65357fe60
|
|||
283abbf0e7d20176f76006825b5c52e9a4234e4c
|
||||
# format libstd/sys
|
||||
c34fbfaad38cf5829ef5cfe780dc9d58480adeaa
|
||||
# move tests
|
||||
cf2dff2b1e3fa55fa5415d524200070d0d7aacfe
|
||||
|
|
|
|||
46
.github/ISSUE_TEMPLATE/diagnostics.md
vendored
46
.github/ISSUE_TEMPLATE/diagnostics.md
vendored
|
|
@ -1,46 +0,0 @@
|
|||
---
|
||||
name: Diagnostic issue
|
||||
about: Create a bug report or feature request for a change to `rustc`'s error output
|
||||
labels: A-diagnostics, T-compiler
|
||||
---
|
||||
<!--
|
||||
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
||||
along with any information you feel relevant to replicating the bug.
|
||||
|
||||
If you cannot produce a minimal reproduction case (something that would work in
|
||||
isolation), please provide the steps or even link to a repository that causes
|
||||
the problematic output to occur.
|
||||
-->
|
||||
|
||||
Given the following code: <!-- Please provide a link to play.rust-lang.org -->
|
||||
|
||||
```rust
|
||||
<code>
|
||||
```
|
||||
|
||||
The current output is:
|
||||
|
||||
```
|
||||
<rustc output>
|
||||
```
|
||||
|
||||
<!-- The following is not always necessary. -->
|
||||
Ideally the output should look like:
|
||||
|
||||
```
|
||||
<proposed output>
|
||||
```
|
||||
|
||||
<!--
|
||||
If the problem is not self-explanatory, please provide a rationale for the
|
||||
change.
|
||||
-->
|
||||
|
||||
<!--
|
||||
If dramatically different output is caused by small changes, consider also
|
||||
adding them here.
|
||||
|
||||
If you're using the stable version of the compiler, you should also check if the
|
||||
bug also exists in the beta or nightly versions. The output might also be
|
||||
different depending on the Edition.
|
||||
-->
|
||||
65
.github/ISSUE_TEMPLATE/diagnostics.yaml
vendored
Normal file
65
.github/ISSUE_TEMPLATE/diagnostics.yaml
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
name: Diagnostic issue
|
||||
description: Create a bug report or feature request for a change to `rustc`'s error output
|
||||
labels: ["A-diagnostics", "T-compiler"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for filing a diagnostics bug report! 🐛
|
||||
|
||||
Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug.
|
||||
|
||||
If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur.
|
||||
- type: textarea
|
||||
id: code
|
||||
attributes:
|
||||
label: Code
|
||||
description: Please provide code that can reproduce the problem
|
||||
placeholder: code
|
||||
render: Rust
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: output
|
||||
attributes:
|
||||
label: Current output
|
||||
description: Please provide the `rustc` output you see
|
||||
placeholder: rustc output
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: desired-output
|
||||
attributes:
|
||||
label: Desired output
|
||||
description: Please provide what the output *should* be
|
||||
placeholder: proposed output
|
||||
render: Shell
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: rationale
|
||||
attributes:
|
||||
label: Rationale and extra context
|
||||
description: If the problem is not self-explanatory, please provide a rationale for the change.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: other-output
|
||||
attributes:
|
||||
label: Other cases
|
||||
description: If dramatically different output is caused by small changes, consider also adding them here.
|
||||
render: Rust
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition.
|
||||
- type: textarea
|
||||
id: extra
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: If you have more details you want to give us to reproduce this issue, please add it here
|
||||
validations:
|
||||
required: false
|
||||
31
.github/ISSUE_TEMPLATE/documentation.md
vendored
31
.github/ISSUE_TEMPLATE/documentation.md
vendored
|
|
@ -1,31 +0,0 @@
|
|||
---
|
||||
name: Documentation problem
|
||||
about: Create a report for a documentation problem.
|
||||
labels: A-docs
|
||||
---
|
||||
<!--
|
||||
|
||||
Thank you for finding a documentation problem! 📚
|
||||
|
||||
Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
|
||||
|
||||
Note: If your issue is for one of these, please use their dedicated issue tracker instead:
|
||||
|
||||
- The Rust Book: https://github.com/rust-lang/book/issues
|
||||
- Rust by Example: https://github.com/rust-lang/rust-by-example/issues
|
||||
- The Edition Guide: https://github.com/rust-lang/edition-guide/issues
|
||||
- The Cargo Book: https://github.com/rust-lang/cargo/issues
|
||||
- The Clippy Book: https://github.com/rust-lang/rust-clippy/issues
|
||||
- The Reference: https://github.com/rust-lang/reference/issues
|
||||
- The Rustonomicon: https://github.com/rust-lang/nomicon/issues
|
||||
- The Embedded Book: https://github.com/rust-embedded/book/issues
|
||||
|
||||
All other documentation issues should be filed here.
|
||||
|
||||
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
|
||||
|
||||
-->
|
||||
|
||||
### Location
|
||||
|
||||
### Summary
|
||||
38
.github/ISSUE_TEMPLATE/documentation.yaml
vendored
Normal file
38
.github/ISSUE_TEMPLATE/documentation.yaml
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
name: Documentation problem
|
||||
description: Create a report for a documentation problem.
|
||||
labels: ["A-docs"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for finding a documentation problem! 📚
|
||||
|
||||
Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
|
||||
|
||||
Note: If your issue is for one of these, please use their dedicated issue tracker instead:
|
||||
- [The Rust Book](https://github.com/rust-lang/book/issues)
|
||||
- [Rust by Example](https://github.com/rust-lang/rust-by-example/issues)
|
||||
- [The Edition Guide](https://github.com/rust-lang/edition-guide/issues)
|
||||
- [The Cargo Book](https://github.com/rust-lang/cargo/issues)
|
||||
- [The Clippy Book](https://github.com/rust-lang/rust-clippy/issues)
|
||||
- [The Reference](https://github.com/rust-lang/reference/issues)
|
||||
- [The Rustonomicon](https://github.com/rust-lang/nomicon/issues)
|
||||
- [The Embedded Book](https://github.com/rust-embedded/book/issues)
|
||||
|
||||
All other documentation issues should be filed here.
|
||||
|
||||
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
|
||||
|
||||
- type: textarea
|
||||
id: location
|
||||
attributes:
|
||||
label: Location
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: summary
|
||||
attributes:
|
||||
label: Summary
|
||||
validations:
|
||||
required: true
|
||||
52
.github/ISSUE_TEMPLATE/ice.md
vendored
52
.github/ISSUE_TEMPLATE/ice.md
vendored
|
|
@ -1,52 +0,0 @@
|
|||
---
|
||||
name: Internal Compiler Error
|
||||
about: Create a report for an internal compiler error in rustc.
|
||||
labels: C-bug, I-ICE, T-compiler
|
||||
---
|
||||
<!--
|
||||
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
||||
a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
|
||||
how to create smaller examples.
|
||||
|
||||
http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
|
||||
|
||||
-->
|
||||
|
||||
### Code
|
||||
|
||||
```Rust
|
||||
<code>
|
||||
```
|
||||
|
||||
|
||||
### Meta
|
||||
<!--
|
||||
If you're using the stable version of the compiler, you should also check if the
|
||||
bug also exists in the beta or nightly versions.
|
||||
-->
|
||||
|
||||
`rustc --version --verbose`:
|
||||
```
|
||||
<version>
|
||||
```
|
||||
|
||||
### Error output
|
||||
|
||||
```
|
||||
<output>
|
||||
```
|
||||
|
||||
<!--
|
||||
Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
|
||||
environment. E.g. `RUST_BACKTRACE=1 cargo build`.
|
||||
-->
|
||||
<details><summary><strong>Backtrace</strong></summary>
|
||||
<p>
|
||||
|
||||
```
|
||||
<backtrace>
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
82
.github/ISSUE_TEMPLATE/ice.yaml
vendored
Normal file
82
.github/ISSUE_TEMPLATE/ice.yaml
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
name: Internal Compiler Error
|
||||
description: Create a report for an internal compiler error in `rustc`
|
||||
labels: ["C-bug", "I-ICE", "T-compiler"]
|
||||
title: "[ICE]: "
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for finding an Internal Compiler Error! 🧊
|
||||
|
||||
If possible, try to provide a minimal verifiable example.
|
||||
|
||||
You can read "[Rust Bug Minimization Patterns](http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/)" for how to create smaller examples.
|
||||
|
||||
- type: textarea
|
||||
id: code
|
||||
attributes:
|
||||
label: Code
|
||||
description: Please provide code or a link to a repository that can reproduce the problem
|
||||
placeholder: code
|
||||
render: Rust
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Affected release channels
|
||||
description: If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions
|
||||
options:
|
||||
- label: Previous Stable
|
||||
required: false
|
||||
- label: Current Stable
|
||||
required: false
|
||||
- label: Current Beta
|
||||
required: false
|
||||
- label: Current Nightly
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Rust Version
|
||||
description: Please provide the `rustc` version, `rustc --version --verbose`
|
||||
placeholder: |
|
||||
$ rustc --version --verbose
|
||||
rustc 1.XX.Y (SHORTHASH DATE)
|
||||
binary: rustc
|
||||
commit-hash: LONGHASHVALUE
|
||||
commit-date: DATE
|
||||
host: PLATFORMTRIPLE
|
||||
release: 1.XX.Y
|
||||
LLVM version: XX.YY.ZZ
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: output
|
||||
attributes:
|
||||
label: Current error output
|
||||
description: Please provide the `rustc` output you see
|
||||
placeholder: output
|
||||
render: Shell
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: backtrace
|
||||
attributes:
|
||||
label: Backtrace
|
||||
description: Include a backtrace in the code block by setting `RUST_BACKTRACE=full` in your environment, e.g. `RUST_BACKTRACE=full cargo build`
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: extra
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: If you have more details you want to give us to reproduce this issue, please add it here
|
||||
validations:
|
||||
required: false
|
||||
167
Cargo.lock
167
Cargo.lock
|
|
@ -35,6 +35,17 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
|
|
@ -107,7 +118,7 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31"
|
||||
dependencies = [
|
||||
"object",
|
||||
"object 0.29.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -193,7 +204,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"object 0.29.0",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
|
|
@ -340,7 +351,7 @@ dependencies = [
|
|||
"cargo-test-macro",
|
||||
"cargo-test-support",
|
||||
"cargo-util",
|
||||
"clap 4.0.15",
|
||||
"clap 4.0.32",
|
||||
"crates-io",
|
||||
"curl",
|
||||
"curl-sys",
|
||||
|
|
@ -644,26 +655,27 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.0.15"
|
||||
version = "4.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f"
|
||||
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive 4.0.13",
|
||||
"clap_derive 4.0.21",
|
||||
"clap_lex 0.3.0",
|
||||
"is-terminal",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "3.1.1"
|
||||
version = "4.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"
|
||||
checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
|
||||
dependencies = [
|
||||
"clap 3.2.20",
|
||||
"clap 4.0.32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -681,9 +693,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.0.13"
|
||||
version = "4.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
|
||||
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
|
|
@ -1773,9 +1785,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.26.1"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"fallible-iterator",
|
||||
|
|
@ -1886,12 +1898,21 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.7.4",
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
|
||||
dependencies = [
|
||||
"ahash 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.0"
|
||||
|
|
@ -2128,12 +2149,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
"rustc-rayon",
|
||||
"serde",
|
||||
]
|
||||
|
|
@ -2273,7 +2294,7 @@ name = "jsondoclint"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.15",
|
||||
"clap 4.0.32",
|
||||
"fs-err",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
|
|
@ -2529,21 +2550,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mdbook"
|
||||
version = "0.4.21"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23f3e133c6d515528745ffd3b9f0c7d975ae039f0b6abb099f2168daa2afb4f9"
|
||||
checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap 3.2.20",
|
||||
"clap 4.0.32",
|
||||
"clap_complete",
|
||||
"elasticlunr-rs",
|
||||
"env_logger 0.9.0",
|
||||
"env_logger 0.10.0",
|
||||
"handlebars 4.3.3",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"opener",
|
||||
"pulldown-cmark 0.9.2",
|
||||
"regex",
|
||||
|
|
@ -2739,15 +2760,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"hashbrown",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d864c91689fdc196779b98dba0aceac6118594c2df6ee5d943eb6a8df4d107a"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"hashbrown 0.13.1",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "odht"
|
||||
version = "0.3.1"
|
||||
|
|
@ -3013,9 +3043,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.3.0"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
|
||||
checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
|
|
@ -3023,9 +3053,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.3.0"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91"
|
||||
checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
|
|
@ -3033,9 +3063,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.3.0"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad"
|
||||
checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
|
|
@ -3046,13 +3076,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.3.0"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04"
|
||||
checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
"sha-1",
|
||||
"sha1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3498,7 +3528,7 @@ dependencies = [
|
|||
name = "rustbook"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 3.2.20",
|
||||
"clap 4.0.32",
|
||||
"env_logger 0.7.1",
|
||||
"mdbook",
|
||||
]
|
||||
|
|
@ -3790,7 +3820,7 @@ dependencies = [
|
|||
"cstr",
|
||||
"libc",
|
||||
"measureme",
|
||||
"object",
|
||||
"object 0.30.1",
|
||||
"rustc-demangle",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
|
@ -3825,7 +3855,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"object",
|
||||
"object 0.30.1",
|
||||
"pathdiff",
|
||||
"regex",
|
||||
"rustc_arena",
|
||||
|
|
@ -4273,6 +4303,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"rustc_span",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-subscriber",
|
||||
"tracing-tree",
|
||||
]
|
||||
|
|
@ -4683,7 +4714,7 @@ dependencies = [
|
|||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
"scoped-tls",
|
||||
"sha-1",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"tracing",
|
||||
"unicode-width",
|
||||
|
|
@ -5092,17 +5123,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
|
|
@ -5305,11 +5325,11 @@ dependencies = [
|
|||
"core",
|
||||
"dlmalloc",
|
||||
"fortanix-sgx-abi",
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
"hermit-abi 0.2.6",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"object 0.29.0",
|
||||
"panic_abort",
|
||||
"panic_unwind",
|
||||
"profiler_builtins",
|
||||
|
|
@ -5477,6 +5497,16 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termize"
|
||||
version = "0.1.1"
|
||||
|
|
@ -5528,18 +5558,18 @@ checksum = "ceb05e71730d396f960f8f3901cdb41be2d339b303e9d7d3a07c5ff0536e671b"
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.33"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57"
|
||||
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.33"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09"
|
||||
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -5548,13 +5578,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thorin-dwp"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254"
|
||||
checksum = "da8fbf660a019b6bf11ea95762041464aa9099cc293b6a66d77cea5107619671"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
"hashbrown",
|
||||
"object",
|
||||
"hashbrown 0.12.3",
|
||||
"object 0.30.1",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -5571,6 +5601,7 @@ dependencies = [
|
|||
name = "tidy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cargo_metadata 0.14.0",
|
||||
"ignore",
|
||||
"lazy_static",
|
||||
|
|
@ -5692,9 +5723,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "topological-sort"
|
||||
version = "0.1.0"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c"
|
||||
checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
|
|
@ -5820,9 +5851,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
|
||||
|
||||
[[package]]
|
||||
name = "ui_test"
|
||||
|
|
@ -6089,9 +6120,9 @@ checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
|
|||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vte"
|
||||
|
|
|
|||
|
|
@ -1100,7 +1100,7 @@ pub enum FieldsShape {
|
|||
/// named `inverse_memory_index`.
|
||||
///
|
||||
// FIXME(eddyb) build a better abstraction for permutations, if possible.
|
||||
// FIXME(camlorn) also consider small vector optimization here.
|
||||
// FIXME(camlorn) also consider small vector optimization here.
|
||||
memory_index: Vec<u32>,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -416,8 +416,7 @@ fn compute_hir_hash(
|
|||
|
||||
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
let sess = tcx.sess;
|
||||
let krate = tcx.untracked_crate.steal();
|
||||
let mut resolver = tcx.resolver_for_lowering(()).steal();
|
||||
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
|
||||
|
||||
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
|
||||
let mut owners = IndexVec::from_fn_n(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_errors::{
|
|||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
|
|
@ -20,7 +21,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty
|
|||
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ use crate::borrowck_errors;
|
|||
|
||||
use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
|
||||
use crate::diagnostics::find_all_local_uses;
|
||||
use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
|
||||
use crate::{
|
||||
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
|
||||
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
|
||||
|
|
@ -356,7 +358,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(_, _, body_id),
|
||||
..
|
||||
})) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
|
||||
})) = hir.find(self.mir_hir_id())
|
||||
&& let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
|
||||
{
|
||||
let place = &self.move_data.move_paths[mpi].place;
|
||||
|
|
@ -948,7 +950,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
|
||||
first_borrow_desc = "immutable ";
|
||||
self.cannot_reborrow_already_borrowed(
|
||||
let mut err = self.cannot_reborrow_already_borrowed(
|
||||
span,
|
||||
&desc_place,
|
||||
&msg_place,
|
||||
|
|
@ -958,7 +960,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"immutable",
|
||||
&msg_borrow,
|
||||
None,
|
||||
)
|
||||
);
|
||||
self.suggest_binding_for_closure_capture_self(
|
||||
&mut err,
|
||||
issued_borrow.borrowed_place,
|
||||
&issued_spans,
|
||||
);
|
||||
err
|
||||
}
|
||||
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
|
||||
|
|
@ -1240,6 +1248,138 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn suggest_binding_for_closure_capture_self(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
borrowed_place: Place<'tcx>,
|
||||
issued_spans: &UseSpans<'tcx>,
|
||||
) {
|
||||
let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
|
||||
let hir = self.infcx.tcx.hir();
|
||||
|
||||
// check whether the borrowed place is capturing `self` by mut reference
|
||||
let local = borrowed_place.local;
|
||||
let Some(_) = self
|
||||
.body
|
||||
.local_decls
|
||||
.get(local)
|
||||
.map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
|
||||
|
||||
struct ExpressionFinder<'hir> {
|
||||
capture_span: Span,
|
||||
closure_change_spans: Vec<Span>,
|
||||
closure_arg_span: Option<Span>,
|
||||
in_closure: bool,
|
||||
suggest_arg: String,
|
||||
hir: rustc_middle::hir::map::Map<'hir>,
|
||||
closure_local_id: Option<hir::HirId>,
|
||||
closure_call_changes: Vec<(Span, String)>,
|
||||
}
|
||||
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
|
||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||
if e.span.contains(self.capture_span) {
|
||||
if let hir::ExprKind::Closure(&hir::Closure {
|
||||
movability: None,
|
||||
body,
|
||||
fn_arg_span,
|
||||
fn_decl: hir::FnDecl{ inputs, .. },
|
||||
..
|
||||
}) = e.kind &&
|
||||
let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
|
||||
self.suggest_arg = "this: &Self".to_string();
|
||||
if inputs.len() > 0 {
|
||||
self.suggest_arg.push_str(", ");
|
||||
}
|
||||
self.in_closure = true;
|
||||
self.closure_arg_span = fn_arg_span;
|
||||
self.visit_expr(body);
|
||||
self.in_closure = false;
|
||||
}
|
||||
}
|
||||
if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
|
||||
if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
|
||||
seg.ident.name == kw::SelfLower && self.in_closure {
|
||||
self.closure_change_spans.push(e.span);
|
||||
}
|
||||
}
|
||||
hir::intravisit::walk_expr(self, e);
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
|
||||
if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
|
||||
let Some(init) = local.init
|
||||
{
|
||||
if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
|
||||
movability: None,
|
||||
..
|
||||
}), .. } = init &&
|
||||
init.span.contains(self.capture_span) {
|
||||
self.closure_local_id = Some(*hir_id);
|
||||
}
|
||||
}
|
||||
hir::intravisit::walk_local(self, local);
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
|
||||
if let hir::StmtKind::Semi(e) = s.kind &&
|
||||
let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
|
||||
let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
|
||||
let Res::Local(hir_id) = seg.res &&
|
||||
Some(hir_id) == self.closure_local_id {
|
||||
let (span, arg_str) = if args.len() > 0 {
|
||||
(args[0].span.shrink_to_lo(), "self, ".to_string())
|
||||
} else {
|
||||
let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
|
||||
(span, "(self)".to_string())
|
||||
};
|
||||
self.closure_call_changes.push((span, arg_str));
|
||||
}
|
||||
hir::intravisit::walk_stmt(self, s);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(hir::Node::ImplItem(
|
||||
hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
|
||||
)) = hir.find(self.mir_hir_id()) &&
|
||||
let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
|
||||
let mut finder = ExpressionFinder {
|
||||
capture_span: *capture_kind_span,
|
||||
closure_change_spans: vec![],
|
||||
closure_arg_span: None,
|
||||
in_closure: false,
|
||||
suggest_arg: String::new(),
|
||||
closure_local_id: None,
|
||||
closure_call_changes: vec![],
|
||||
hir,
|
||||
};
|
||||
finder.visit_expr(expr);
|
||||
|
||||
if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut sugg = vec![];
|
||||
let sm = self.infcx.tcx.sess.source_map();
|
||||
|
||||
if let Some(span) = finder.closure_arg_span {
|
||||
sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
|
||||
}
|
||||
for span in finder.closure_change_spans {
|
||||
sugg.push((span, "this".to_string()));
|
||||
}
|
||||
|
||||
for (span, suggest) in finder.closure_call_changes {
|
||||
sugg.push((span, suggest));
|
||||
}
|
||||
|
||||
err.multipart_suggestion_verbose(
|
||||
"try explicitly pass `&Self` into the Closure as an argument",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the description of the root place for a conflicting borrow and the full
|
||||
/// descriptions of the places that caused the conflict.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1094,7 +1094,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
|
||||
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
|
||||
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
|
||||
|
||||
match local_decl.local_info.as_deref() {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ impl<'tcx> RegionErrors<'tcx> {
|
|||
#[track_caller]
|
||||
pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
|
||||
let val = val.into();
|
||||
self.1.sess.delay_span_bug(DUMMY_SP, "{val:?}");
|
||||
self.1.sess.delay_span_bug(DUMMY_SP, format!("{val:?}"));
|
||||
self.0.push(val);
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ fn place_components_conflict<'tcx>(
|
|||
match (elem, &base_ty.kind(), access) {
|
||||
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
||||
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
|
||||
// The array length is like additional fields on the
|
||||
// The array length is like additional fields on the
|
||||
// type; it does not overlap any existing data there.
|
||||
// Furthermore, if cannot actually be a prefix of any
|
||||
// borrowed place (at least in MIR as it is currently.)
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
/// # Parameters
|
||||
///
|
||||
/// - `def_id`, the `impl Trait` type
|
||||
/// - `substs`, the substs used to instantiate this opaque type
|
||||
/// - `substs`, the substs used to instantiate this opaque type
|
||||
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
|
||||
/// `opaque_defn.concrete_ty`
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ bitflags = "1.0"
|
|||
cstr = "0.2"
|
||||
libc = "0.2"
|
||||
measureme = "10.0.0"
|
||||
object = { version = "0.29.0", default-features = false, features = ["std", "read"] }
|
||||
object = { version = "0.30.1", default-features = false, features = [
|
||||
"std",
|
||||
"read",
|
||||
] }
|
||||
tracing = "0.1"
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc-demangle = "0.1.21"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ tracing = "0.1"
|
|||
libc = "0.2.50"
|
||||
jobserver = "0.1.22"
|
||||
tempfile = "3.2"
|
||||
thorin-dwp = "0.3"
|
||||
thorin-dwp = "0.4"
|
||||
pathdiff = "0.2.0"
|
||||
serde_json = "1.0.59"
|
||||
snap = "1"
|
||||
|
|
@ -44,6 +44,6 @@ rustc_session = { path = "../rustc_session" }
|
|||
rustc_const_eval = { path = "../rustc_const_eval" }
|
||||
|
||||
[dependencies.object]
|
||||
version = "0.29.0"
|
||||
version = "0.30.1"
|
||||
default-features = false
|
||||
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
|
||||
|
|
|
|||
|
|
@ -1231,12 +1231,21 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
|||
sess.emit_fatal(errors::LinkerFileStem);
|
||||
});
|
||||
|
||||
// Remove any version postfix.
|
||||
let stem = stem
|
||||
.rsplit_once('-')
|
||||
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
|
||||
.unwrap_or(stem);
|
||||
|
||||
// GCC can have an optional target prefix.
|
||||
let flavor = if stem == "emcc" {
|
||||
LinkerFlavor::EmCc
|
||||
} else if stem == "gcc"
|
||||
|| stem.ends_with("-gcc")
|
||||
|| stem == "g++"
|
||||
|| stem.ends_with("-g++")
|
||||
|| stem == "clang"
|
||||
|| stem.ends_with("-clang")
|
||||
|| stem == "clang++"
|
||||
{
|
||||
LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
|
||||
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,13 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
|||
};
|
||||
let architecture = match &sess.target.arch[..] {
|
||||
"arm" => Architecture::Arm,
|
||||
"aarch64" => Architecture::Aarch64,
|
||||
"aarch64" => {
|
||||
if sess.target.pointer_width == 32 {
|
||||
Architecture::Aarch64_Ilp32
|
||||
} else {
|
||||
Architecture::Aarch64
|
||||
}
|
||||
}
|
||||
"x86" => Architecture::I386,
|
||||
"s390x" => Architecture::S390x,
|
||||
"mips" => Architecture::Mips,
|
||||
|
|
@ -165,11 +171,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
|||
};
|
||||
e_flags
|
||||
}
|
||||
Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
|
||||
// copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
|
||||
// that the `+d` target feature represents whether the double
|
||||
// float abi is enabled.
|
||||
let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
|
||||
Architecture::Riscv32 | Architecture::Riscv64 => {
|
||||
// Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
|
||||
let mut e_flags: u32 = 0x0;
|
||||
let features = &sess.target.options.features;
|
||||
// Check if compressed is enabled
|
||||
if features.contains("+c") {
|
||||
e_flags |= elf::EF_RISCV_RVC;
|
||||
}
|
||||
|
||||
// Select the appropriate floating-point ABI
|
||||
if features.contains("+d") {
|
||||
e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE;
|
||||
} else if features.contains("+f") {
|
||||
e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE;
|
||||
} else {
|
||||
e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT;
|
||||
}
|
||||
e_flags
|
||||
}
|
||||
_ => 0,
|
||||
|
|
|
|||
|
|
@ -231,6 +231,10 @@ fn run_compiler(
|
|||
registry: diagnostics_registry(),
|
||||
};
|
||||
|
||||
if !tracing::dispatcher::has_been_set() {
|
||||
init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace);
|
||||
}
|
||||
|
||||
match make_input(config.opts.error_format, &matches.free) {
|
||||
Err(reported) => return Err(reported),
|
||||
Ok(Some((input, input_file_path))) => {
|
||||
|
|
@ -1300,7 +1304,14 @@ pub fn install_ice_hook() {
|
|||
/// This allows tools to enable rust logging without having to magically match rustc's
|
||||
/// tracing crate version.
|
||||
pub fn init_rustc_env_logger() {
|
||||
if let Err(error) = rustc_log::init_rustc_env_logger() {
|
||||
init_rustc_env_logger_with_backtrace_option(&None);
|
||||
}
|
||||
|
||||
/// This allows tools to enable rust logging without having to magically match rustc's
|
||||
/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to
|
||||
/// choose a target module you wish to show backtraces along with its logging.
|
||||
pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) {
|
||||
if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) {
|
||||
early_error(ErrorOutputType::default(), &error.to_string());
|
||||
}
|
||||
}
|
||||
|
|
@ -1366,7 +1377,6 @@ mod signal_handler {
|
|||
pub fn main() -> ! {
|
||||
let start_time = Instant::now();
|
||||
let start_rss = get_resident_set_size();
|
||||
init_rustc_env_logger();
|
||||
signal_handler::install();
|
||||
let mut callbacks = TimePassesCallbacks::default();
|
||||
install_ice_hook();
|
||||
|
|
|
|||
|
|
@ -46,3 +46,14 @@ hir_typeck_add_missing_parentheses_in_range = you must surround the range in par
|
|||
|
||||
hir_typeck_op_trait_generic_params =
|
||||
`{$method_name}` must not have any generic parameters
|
||||
|
||||
hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
|
||||
hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
|
||||
|
||||
hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
|
||||
|
||||
hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect
|
||||
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
|
||||
|
||||
hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
|
||||
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
|
||||
|
|
|
|||
|
|
@ -41,3 +41,6 @@ interface_rustc_error_unexpected_annotation =
|
|||
|
||||
interface_failed_writing_file =
|
||||
failed to write file {$path}: {$error}"
|
||||
|
||||
interface_proc_macro_crate_panic_abort =
|
||||
building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
-passes_see_issue =
|
||||
see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information
|
||||
|
||||
passes_incorrect_do_not_recommend_location =
|
||||
`#[do_not_recommend]` can only be placed on trait implementations
|
||||
|
||||
passes_outer_crate_level_attr =
|
||||
crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
|
||||
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@ use rustc_span::edition::Edition;
|
|||
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, FileName, RealFileName, Span, DUMMY_SP};
|
||||
use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use std::iter;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(crate) use rustc_span::hygiene::MacroKind;
|
||||
|
|
@ -1423,8 +1423,10 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
|
|||
if let [variant] = &*enum_def.variants {
|
||||
if variant.ident.name == sym::Input {
|
||||
let filename = sess.source_map().span_to_filename(item.ident.span);
|
||||
if let FileName::Real(RealFileName::LocalPath(path)) = filename {
|
||||
if let Some(c) = path
|
||||
if let FileName::Real(real) = filename {
|
||||
if let Some(c) = real
|
||||
.local_path()
|
||||
.unwrap_or(Path::new(""))
|
||||
.components()
|
||||
.flat_map(|c| c.as_os_str().to_str())
|
||||
.find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
||||
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::middle::stability::AllowUnstable;
|
||||
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
|
|
@ -510,9 +511,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
return tcx.const_error(ty).into();
|
||||
}
|
||||
if !infer_args && has_default {
|
||||
tcx.bound_const_param_default(param.def_id)
|
||||
.subst(tcx, substs.unwrap())
|
||||
.into()
|
||||
tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
|
||||
} else {
|
||||
if infer_args {
|
||||
self.astconv.ct_infer(ty, Some(param), self.span).into()
|
||||
|
|
@ -1643,8 +1642,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
fn report_ambiguous_associated_type(
|
||||
&self,
|
||||
span: Span,
|
||||
type_str: &str,
|
||||
trait_str: &str,
|
||||
types: &[String],
|
||||
traits: &[String],
|
||||
name: Symbol,
|
||||
) -> ErrorGuaranteed {
|
||||
let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
|
||||
|
|
@ -1655,19 +1654,92 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.keys()
|
||||
.any(|full_span| full_span.contains(span))
|
||||
{
|
||||
err.span_suggestion(
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"you are looking for the module in `std`, not the primitive type",
|
||||
"std::",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"use fully-qualified syntax",
|
||||
format!("<{} as {}>::{}", type_str, trait_str, name),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
match (types, traits) {
|
||||
([], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a type named `Type` that implements a trait named \
|
||||
`Trait` with associated type `{name}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
format!("<Type as Trait>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], [trait_str]) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a type named `Example` that implemented `{trait_str}`, \
|
||||
you could use the fully-qualified path",
|
||||
),
|
||||
format!("<Example as {trait_str}>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], traits) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a type named `Example` that implemented one of the \
|
||||
traits with associated type `{name}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
traits
|
||||
.iter()
|
||||
.map(|trait_str| format!("<Example as {trait_str}>::{name}"))
|
||||
.collect::<Vec<_>>(),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([type_str], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a trait named `Example` with associated type `{name}` \
|
||||
implemented for `{type_str}`, you could use the fully-qualified path",
|
||||
),
|
||||
format!("<{type_str} as Example>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
(types, []) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
&format!(
|
||||
"if there were a trait named `Example` with associated type `{name}` \
|
||||
implemented for one of the types, you could use the fully-qualified \
|
||||
path",
|
||||
),
|
||||
types
|
||||
.into_iter()
|
||||
.map(|type_str| format!("<{type_str} as Example>::{name}")),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
(types, traits) => {
|
||||
let mut suggestions = vec![];
|
||||
for type_str in types {
|
||||
for trait_str in traits {
|
||||
suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
|
||||
}
|
||||
}
|
||||
err.span_suggestions(
|
||||
span,
|
||||
"use the fully-qualified path",
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
err.emit()
|
||||
}
|
||||
|
|
@ -1994,7 +2066,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
};
|
||||
|
||||
self.one_bound_for_assoc_type(
|
||||
|| traits::supertraits(tcx, ty::Binder::dummy(trait_ref)),
|
||||
|| traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())),
|
||||
|| "Self".to_string(),
|
||||
assoc_ident,
|
||||
span,
|
||||
|
|
@ -2050,12 +2122,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
err.emit()
|
||||
} else if let Err(reported) = qself_ty.error_reported() {
|
||||
reported
|
||||
} else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
|
||||
// `<impl Trait as OtherTrait>::Assoc` makes no sense.
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
tcx.def_span(alias_ty.def_id),
|
||||
E0667,
|
||||
"`impl Trait` is not allowed in path parameters"
|
||||
)
|
||||
.emit() // Already reported in an earlier stage.
|
||||
} else {
|
||||
// Find all the `impl`s that `qself_ty` has for any trait that has the
|
||||
// associated type, so that we suggest the right one.
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
// We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
|
||||
// to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
let traits: Vec<_> = self
|
||||
.tcx()
|
||||
.all_traits()
|
||||
.filter(|trait_def_id| {
|
||||
// Consider only traits with the associated type
|
||||
tcx.associated_items(*trait_def_id)
|
||||
.in_definition_order()
|
||||
.any(|i| {
|
||||
i.kind.namespace() == Namespace::TypeNS
|
||||
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
|
||||
&& matches!(i.kind, ty::AssocKind::Type)
|
||||
})
|
||||
// Consider only accessible traits
|
||||
&& tcx.visibility(*trait_def_id)
|
||||
.is_accessible_from(self.item_def_id(), tcx)
|
||||
&& tcx.all_impls(*trait_def_id)
|
||||
.any(|impl_def_id| {
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id);
|
||||
trait_ref.map_or(false, |trait_ref| {
|
||||
let impl_ = trait_ref.subst(
|
||||
tcx,
|
||||
infcx.fresh_substs_for_item(span, impl_def_id),
|
||||
);
|
||||
infcx
|
||||
.can_eq(
|
||||
param_env,
|
||||
tcx.erase_regions(impl_.self_ty()),
|
||||
tcx.erase_regions(qself_ty),
|
||||
)
|
||||
.is_ok()
|
||||
})
|
||||
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
|
||||
})
|
||||
})
|
||||
.map(|trait_def_id| tcx.def_path_str(trait_def_id))
|
||||
.collect();
|
||||
|
||||
// Don't print `TyErr` to the user.
|
||||
self.report_ambiguous_associated_type(
|
||||
span,
|
||||
&qself_ty.to_string(),
|
||||
"Trait",
|
||||
&[qself_ty.to_string()],
|
||||
&traits,
|
||||
assoc_ident.name,
|
||||
)
|
||||
};
|
||||
|
|
@ -2173,16 +2297,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let is_part_of_self_trait_constraints = def_id == trait_def_id;
|
||||
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
|
||||
|
||||
let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
"Self"
|
||||
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
vec!["Self".to_string()]
|
||||
} else {
|
||||
"Type"
|
||||
// Find all the types that have an `impl` for the trait.
|
||||
tcx.all_impls(trait_def_id)
|
||||
.filter(|impl_def_id| {
|
||||
// Consider only accessible traits
|
||||
tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx)
|
||||
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
|
||||
})
|
||||
.filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
|
||||
.map(|impl_| impl_.subst_identity().self_ty())
|
||||
// We don't care about blanket impls.
|
||||
.filter(|self_ty| !self_ty.has_non_region_param())
|
||||
.map(|self_ty| tcx.erase_regions(self_ty).to_string())
|
||||
.collect()
|
||||
};
|
||||
|
||||
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
|
||||
// references the trait. Relevant for the first case in
|
||||
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
|
||||
let reported = self.report_ambiguous_associated_type(
|
||||
span,
|
||||
type_name,
|
||||
&path_str,
|
||||
&type_names,
|
||||
&[path_str],
|
||||
item_segment.ident.name,
|
||||
);
|
||||
return tcx.ty_error_with_guaranteed(reported)
|
||||
|
|
@ -3167,7 +3305,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let label = "add `dyn` keyword before this trait";
|
||||
let mut diag =
|
||||
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
|
||||
diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
|
||||
if self_ty.span.can_be_used_for_suggestions() {
|
||||
diag.multipart_suggestion_verbose(
|
||||
label,
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// check if the impl trait that we are considering is a impl of a local trait
|
||||
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
|
||||
diag.emit();
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
tcx,
|
||||
it.span,
|
||||
it.owner_id.def_id,
|
||||
impl_trait_ref,
|
||||
impl_trait_ref.subst_identity(),
|
||||
&impl_.items,
|
||||
);
|
||||
check_on_unimplemented(tcx, it);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ use super::potentially_plural_count;
|
|||
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
||||
use hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
|
||||
use rustc_errors::{
|
||||
pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit;
|
||||
|
|
@ -320,15 +322,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
|
||||
));
|
||||
}
|
||||
let emit_implied_wf_lint = || {
|
||||
infcx.tcx.struct_span_lint_hir(
|
||||
rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
|
||||
impl_m_hir_id,
|
||||
infcx.tcx.def_span(impl_m.def_id),
|
||||
"impl method assumes more implied bounds than the corresponding trait method",
|
||||
|lint| lint,
|
||||
);
|
||||
};
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
|
|
@ -346,7 +339,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
)
|
||||
.map(|()| {
|
||||
// If the skip-mode was successful, emit a lint.
|
||||
emit_implied_wf_lint();
|
||||
emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]);
|
||||
});
|
||||
}
|
||||
CheckImpliedWfMode::Skip => {
|
||||
|
|
@ -382,8 +375,16 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
CheckImpliedWfMode::Skip,
|
||||
)
|
||||
.map(|()| {
|
||||
let bad_args = extract_bad_args_for_implies_lint(
|
||||
tcx,
|
||||
&errors,
|
||||
(trait_m, trait_sig),
|
||||
// Unnormalized impl sig corresponds to the HIR types written
|
||||
(impl_m, unnormalized_impl_sig),
|
||||
impl_m_hir_id,
|
||||
);
|
||||
// If the skip-mode was successful, emit a lint.
|
||||
emit_implied_wf_lint();
|
||||
emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args);
|
||||
});
|
||||
}
|
||||
CheckImpliedWfMode::Skip => {
|
||||
|
|
@ -400,6 +401,141 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn extract_bad_args_for_implies_lint<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
errors: &[infer::RegionResolutionError<'tcx>],
|
||||
(trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
|
||||
(impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
|
||||
hir_id: hir::HirId,
|
||||
) -> Vec<(Span, Option<String>)> {
|
||||
let mut blame_generics = vec![];
|
||||
for error in errors {
|
||||
// Look for the subregion origin that contains an input/output type
|
||||
let origin = match error {
|
||||
infer::RegionResolutionError::ConcreteFailure(o, ..) => o,
|
||||
infer::RegionResolutionError::GenericBoundFailure(o, ..) => o,
|
||||
infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o,
|
||||
infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o,
|
||||
};
|
||||
// Extract (possible) input/output types from origin
|
||||
match origin {
|
||||
infer::SubregionOrigin::Subtype(trace) => {
|
||||
if let Some((a, b)) = trace.values.ty() {
|
||||
blame_generics.extend([a, b]);
|
||||
}
|
||||
}
|
||||
infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty),
|
||||
infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap();
|
||||
let opt_ret_ty = match fn_decl.output {
|
||||
hir::FnRetTy::DefaultReturn(_) => None,
|
||||
hir::FnRetTy::Return(ty) => Some(ty),
|
||||
};
|
||||
|
||||
// Map late-bound regions from trait to impl, so the names are right.
|
||||
let mapping = std::iter::zip(
|
||||
tcx.fn_sig(trait_m.def_id).bound_vars(),
|
||||
tcx.fn_sig(impl_m.def_id).bound_vars(),
|
||||
)
|
||||
.filter_map(|(impl_bv, trait_bv)| {
|
||||
if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
|
||||
&& let ty::BoundVariableKind::Region(trait_bv) = trait_bv
|
||||
{
|
||||
Some((impl_bv, trait_bv))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// For each arg, see if it was in the "blame" of any of the region errors.
|
||||
// If so, then try to produce a suggestion to replace the argument type with
|
||||
// one from the trait.
|
||||
let mut bad_args = vec![];
|
||||
for (idx, (ty, hir_ty)) in
|
||||
std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty))
|
||||
.enumerate()
|
||||
{
|
||||
let expected_ty = trait_sig.inputs_and_output[idx]
|
||||
.fold_with(&mut RemapLateBound { tcx, mapping: &mapping });
|
||||
if blame_generics.iter().any(|blame| ty.contains(*blame)) {
|
||||
let expected_ty_sugg = expected_ty.to_string();
|
||||
bad_args.push((
|
||||
hir_ty.span,
|
||||
// Only suggest something if it actually changed.
|
||||
(expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
bad_args
|
||||
}
|
||||
|
||||
struct RemapLateBound<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<'tcx> for RemapLateBound<'_, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
if let ty::ReFree(fr) = *r {
|
||||
self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
|
||||
bound_region: self
|
||||
.mapping
|
||||
.get(&fr.bound_region)
|
||||
.copied()
|
||||
.unwrap_or(fr.bound_region),
|
||||
..fr
|
||||
}))
|
||||
} else {
|
||||
r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_implied_wf_lint<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_m: &ty::AssocItem,
|
||||
hir_id: hir::HirId,
|
||||
bad_args: Vec<(Span, Option<String>)>,
|
||||
) {
|
||||
let span: MultiSpan = if bad_args.is_empty() {
|
||||
tcx.def_span(impl_m.def_id).into()
|
||||
} else {
|
||||
bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into()
|
||||
};
|
||||
tcx.struct_span_lint_hir(
|
||||
rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
|
||||
hir_id,
|
||||
span,
|
||||
"impl method assumes more implied bounds than the corresponding trait method",
|
||||
|lint| {
|
||||
let bad_args: Vec<_> =
|
||||
bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect();
|
||||
if !bad_args.is_empty() {
|
||||
lint.multipart_suggestion(
|
||||
format!(
|
||||
"replace {} type{} to make the impl signature compatible",
|
||||
pluralize!("this", bad_args.len()),
|
||||
pluralize!(bad_args.len())
|
||||
),
|
||||
bad_args,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
lint
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum CheckImpliedWfMode {
|
||||
/// Checks implied well-formedness of the impl method. If it fails, we will
|
||||
|
|
@ -480,7 +616,8 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
|
||||
let impl_m = tcx.opt_associated_item(def_id).unwrap();
|
||||
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
|
||||
let impl_trait_ref =
|
||||
tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity();
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
||||
// First, check a few of the same things as `compare_impl_method`,
|
||||
|
|
@ -1548,7 +1685,8 @@ pub(super) fn compare_impl_const_raw(
|
|||
) -> Result<(), ErrorGuaranteed> {
|
||||
let impl_const_item = tcx.associated_item(impl_const_item_def);
|
||||
let trait_const_item = tcx.associated_item(trait_const_item_def);
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
|
||||
let impl_trait_ref =
|
||||
tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().subst_identity();
|
||||
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
|
||||
|
||||
let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
|||
hir::ItemKind::Impl(ref impl_) => {
|
||||
let is_auto = tcx
|
||||
.impl_trait_ref(def_id)
|
||||
.map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
|
||||
.map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
|
||||
if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
|
||||
let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
|
||||
let mut err =
|
||||
|
|
@ -1253,8 +1253,12 @@ fn check_impl<'tcx>(
|
|||
// `#[rustc_reservation_impl]` impls are not real impls and
|
||||
// therefore don't need to be WF (the trait's `Self: Trait` predicate
|
||||
// won't hold).
|
||||
let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
|
||||
let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
|
||||
let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().subst_identity();
|
||||
let trait_ref = wfcx.normalize(
|
||||
ast_trait_ref.path.span,
|
||||
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
|
||||
trait_ref,
|
||||
);
|
||||
let trait_pred = ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: match constness {
|
||||
|
|
@ -1263,7 +1267,7 @@ fn check_impl<'tcx>(
|
|||
},
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
};
|
||||
let obligations = traits::wf::trait_obligations(
|
||||
let mut obligations = traits::wf::trait_obligations(
|
||||
wfcx.infcx,
|
||||
wfcx.param_env,
|
||||
wfcx.body_id,
|
||||
|
|
@ -1271,6 +1275,13 @@ fn check_impl<'tcx>(
|
|||
ast_trait_ref.path.span,
|
||||
item,
|
||||
);
|
||||
for obligation in &mut obligations {
|
||||
if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred()
|
||||
&& pred.self_ty().skip_binder() == trait_ref.self_ty()
|
||||
{
|
||||
obligation.cause.span = ast_self_ty.span;
|
||||
}
|
||||
}
|
||||
debug!(?obligations);
|
||||
wfcx.register_obligations(obligations);
|
||||
}
|
||||
|
|
@ -1339,7 +1350,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
// is incorrect when dealing with unused substs, for example
|
||||
// for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
|
||||
// we should eagerly error.
|
||||
let default_ct = tcx.const_param_default(param.def_id);
|
||||
let default_ct = tcx.const_param_default(param.def_id).subst_identity();
|
||||
if !default_ct.needs_subst() {
|
||||
wfcx.register_wf_obligation(
|
||||
tcx.def_span(param.def_id),
|
||||
|
|
@ -1385,7 +1396,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
GenericParamDefKind::Const { .. } => {
|
||||
// If the param has a default, ...
|
||||
if is_our_default(param) {
|
||||
let default_ct = tcx.const_param_default(param.def_id);
|
||||
let default_ct = tcx.const_param_default(param.def_id).subst_identity();
|
||||
// ... and it's not a dependent default, ...
|
||||
if !default_ct.needs_subst() {
|
||||
// ... then substitute it with the default.
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
|
|||
let source = tcx.type_of(impl_did);
|
||||
assert!(!source.has_escaping_bound_vars());
|
||||
let target = {
|
||||
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
|
||||
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
|
||||
assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
|
||||
|
||||
trait_ref.substs.type_at(1)
|
||||
|
|
@ -354,7 +354,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
|
|||
});
|
||||
|
||||
let source = tcx.type_of(impl_did);
|
||||
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
|
||||
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
|
||||
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
|
||||
let target = trait_ref.substs.type_at(1);
|
||||
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
|
|||
|
||||
let impls = tcx.hir().trait_impls(def_id);
|
||||
for &impl_def_id in impls {
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
|
||||
|
||||
check_impl(tcx, impl_def_id, trait_ref);
|
||||
check_object_overlap(tcx, impl_def_id, trait_ref);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ pub(crate) fn orphan_check_impl(
|
|||
tcx: TyCtxt<'_>,
|
||||
impl_def_id: LocalDefId,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
|
||||
trait_ref.error_reported()?;
|
||||
|
||||
let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
|
||||
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
|
||||
let trait_ref = trait_ref.subst_identity();
|
||||
let trait_def = tcx.trait_def(trait_ref.def_id);
|
||||
let unsafe_attr =
|
||||
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
|
||||
|
|
|
|||
|
|
@ -1339,18 +1339,22 @@ fn suggest_impl_trait<'tcx>(
|
|||
None
|
||||
}
|
||||
|
||||
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
|
||||
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let item = tcx.hir().expect_item(def_id.expect_local());
|
||||
match item.kind {
|
||||
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
|
||||
let selfty = tcx.type_of(def_id);
|
||||
icx.astconv().instantiate_mono_trait_ref(
|
||||
ast_trait_ref,
|
||||
selfty,
|
||||
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
|
||||
)
|
||||
}),
|
||||
hir::ItemKind::Impl(ref impl_) => impl_
|
||||
.of_trait
|
||||
.as_ref()
|
||||
.map(|ast_trait_ref| {
|
||||
let selfty = tcx.type_of(def_id);
|
||||
icx.astconv().instantiate_mono_trait_ref(
|
||||
ast_trait_ref,
|
||||
selfty,
|
||||
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
|
||||
)
|
||||
})
|
||||
.map(ty::EarlyBinder),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
|||
Node::Item(item) => match item.kind {
|
||||
ItemKind::Impl(ref impl_) => {
|
||||
if impl_.defaultness.is_default() {
|
||||
is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
|
||||
is_default_impl_trait =
|
||||
tcx.impl_trait_ref(def_id).map(|t| ty::Binder::dummy(t.subst_identity()));
|
||||
}
|
||||
&impl_.generics
|
||||
}
|
||||
|
|
@ -251,7 +252,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
|||
// for details.
|
||||
if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
|
||||
let self_ty = tcx.type_of(def_id);
|
||||
let trait_ref = tcx.impl_trait_ref(def_id);
|
||||
let trait_ref = tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::subst_identity);
|
||||
cgp::setup_constraining_predicates(
|
||||
tcx,
|
||||
&mut predicates,
|
||||
|
|
|
|||
|
|
@ -114,34 +114,46 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
// Get the starting `hir::Ty` using our `WellFormedLoc`.
|
||||
// We will walk 'into' this type to try to find
|
||||
// a more precise span for our predicate.
|
||||
let ty = match loc {
|
||||
let tys = match loc {
|
||||
WellFormedLoc::Ty(_) => match hir.get(hir_id) {
|
||||
hir::Node::ImplItem(item) => match item.kind {
|
||||
hir::ImplItemKind::Type(ty) => Some(ty),
|
||||
hir::ImplItemKind::Const(ty, _) => Some(ty),
|
||||
hir::ImplItemKind::Type(ty) => vec![ty],
|
||||
hir::ImplItemKind::Const(ty, _) => vec![ty],
|
||||
ref item => bug!("Unexpected ImplItem {:?}", item),
|
||||
},
|
||||
hir::Node::TraitItem(item) => match item.kind {
|
||||
hir::TraitItemKind::Type(_, ty) => ty,
|
||||
hir::TraitItemKind::Const(ty, _) => Some(ty),
|
||||
hir::TraitItemKind::Type(_, ty) => ty.into_iter().collect(),
|
||||
hir::TraitItemKind::Const(ty, _) => vec![ty],
|
||||
ref item => bug!("Unexpected TraitItem {:?}", item),
|
||||
},
|
||||
hir::Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => Some(ty),
|
||||
hir::ItemKind::Impl(ref impl_) => {
|
||||
assert!(impl_.of_trait.is_none(), "Unexpected trait impl: {:?}", impl_);
|
||||
Some(impl_.self_ty)
|
||||
}
|
||||
hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty],
|
||||
hir::ItemKind::Impl(ref impl_) => match &impl_.of_trait {
|
||||
Some(t) => t
|
||||
.path
|
||||
.segments
|
||||
.last()
|
||||
.iter()
|
||||
.flat_map(|seg| seg.args().args)
|
||||
.filter_map(|arg| {
|
||||
if let hir::GenericArg::Type(ty) = arg { Some(*ty) } else { None }
|
||||
})
|
||||
.chain([impl_.self_ty])
|
||||
.collect(),
|
||||
None => {
|
||||
vec![impl_.self_ty]
|
||||
}
|
||||
},
|
||||
ref item => bug!("Unexpected item {:?}", item),
|
||||
},
|
||||
hir::Node::Field(field) => Some(field.ty),
|
||||
hir::Node::Field(field) => vec![field.ty],
|
||||
hir::Node::ForeignItem(ForeignItem {
|
||||
kind: ForeignItemKind::Static(ty, _), ..
|
||||
}) => Some(*ty),
|
||||
}) => vec![*ty],
|
||||
hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Type { default: Some(ty), .. },
|
||||
..
|
||||
}) => Some(*ty),
|
||||
}) => vec![*ty],
|
||||
ref node => bug!("Unexpected node {:?}", node),
|
||||
},
|
||||
WellFormedLoc::Param { function: _, param_idx } => {
|
||||
|
|
@ -149,16 +161,16 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
// Get return type
|
||||
if param_idx as usize == fn_decl.inputs.len() {
|
||||
match fn_decl.output {
|
||||
hir::FnRetTy::Return(ty) => Some(ty),
|
||||
hir::FnRetTy::Return(ty) => vec![ty],
|
||||
// The unit type `()` is always well-formed
|
||||
hir::FnRetTy::DefaultReturn(_span) => None,
|
||||
hir::FnRetTy::DefaultReturn(_span) => vec![],
|
||||
}
|
||||
} else {
|
||||
Some(&fn_decl.inputs[param_idx as usize])
|
||||
vec![&fn_decl.inputs[param_idx as usize]]
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some(ty) = ty {
|
||||
for ty in tys {
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
visitor.cause
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
|
|||
}
|
||||
let impl_generics = tcx.generics_of(impl_def_id);
|
||||
let impl_predicates = tcx.predicates_of(impl_def_id);
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
|
||||
|
||||
let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
|
||||
cgp::identify_constrained_generic_params(
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
|
|||
|
||||
fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
|
||||
let trait_ref = tcx.impl_trait_ref(impl1_def_id)?;
|
||||
let trait_def = tcx.trait_def(trait_ref.def_id);
|
||||
let trait_def = tcx.trait_def(trait_ref.skip_binder().def_id);
|
||||
|
||||
let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?;
|
||||
|
||||
|
|
@ -207,7 +207,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
|
|||
let impl_generic_predicates = tcx.predicates_of(impl_def_id);
|
||||
let mut unconstrained_parameters = FxHashSet::default();
|
||||
let mut constrained_params = FxHashSet::default();
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
|
||||
|
||||
// Unfortunately the functions in `constrained_generic_parameters` don't do
|
||||
// what we want here. We want only a list of constrained parameters while
|
||||
|
|
@ -370,7 +370,7 @@ fn check_predicates<'tcx>(
|
|||
});
|
||||
|
||||
// Include the well-formed predicates of the type parameters of the impl.
|
||||
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
|
||||
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs {
|
||||
let infcx = &tcx.infer_ctxt().build();
|
||||
let obligations = wf::obligations(
|
||||
infcx,
|
||||
|
|
|
|||
|
|
@ -659,8 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
|
||||
if let Some((maybe_def, output_ty, _)) =
|
||||
self.extract_callable_info(callee_expr, callee_ty)
|
||||
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
|
||||
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
|
||||
{
|
||||
let descr = match maybe_def {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use crate::coercion::CoerceMany;
|
||||
use crate::errors::{
|
||||
LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy,
|
||||
};
|
||||
use crate::gather_locals::GatherLocalsVisitor;
|
||||
use crate::FnCtxt;
|
||||
use crate::GeneratorTypes;
|
||||
|
|
@ -9,8 +12,9 @@ use rustc_hir::lang_items::LangItem;
|
|||
use rustc_hir_analysis::check::fn_maybe_err;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::RegionVariableOrigin;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits;
|
||||
use std::cell::RefCell;
|
||||
|
||||
|
|
@ -168,6 +172,10 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
|
||||
}
|
||||
|
||||
if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == hir.local_def_id(fn_id).to_def_id() {
|
||||
check_lang_start_fn(tcx, fn_sig, decl, fn_def_id);
|
||||
}
|
||||
|
||||
gen_ty
|
||||
}
|
||||
|
||||
|
|
@ -223,3 +231,126 @@ fn check_panic_info_fn(
|
|||
tcx.sess.span_err(span, "should have no const parameters");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lang_start_fn<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_sig: ty::FnSig<'tcx>,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let inputs = fn_sig.inputs();
|
||||
|
||||
let arg_count = inputs.len();
|
||||
if arg_count != 4 {
|
||||
tcx.sess.emit_err(LangStartIncorrectNumberArgs {
|
||||
params_span: tcx.def_span(def_id),
|
||||
found_param_count: arg_count,
|
||||
});
|
||||
}
|
||||
|
||||
// only check args if they should exist by checking the count
|
||||
// note: this does not handle args being shifted or their order swapped very nicely
|
||||
// but it's a lang item, users shouldn't frequently encounter this
|
||||
|
||||
// first arg is `main: fn() -> T`
|
||||
if let Some(&main_arg) = inputs.get(0) {
|
||||
// make a Ty for the generic on the fn for diagnostics
|
||||
// FIXME: make the lang item generic checks check for the right generic *kind*
|
||||
// for example `start`'s generic should be a type parameter
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let fn_generic = generics.param_at(0, tcx);
|
||||
let generic_tykind =
|
||||
ty::Param(ty::ParamTy { index: fn_generic.index, name: fn_generic.name });
|
||||
let generic_ty = tcx.mk_ty(generic_tykind);
|
||||
let expected_fn_sig =
|
||||
tcx.mk_fn_sig([].iter(), &generic_ty, false, hir::Unsafety::Normal, Abi::Rust);
|
||||
let expected_ty = tcx.mk_fn_ptr(Binder::dummy(expected_fn_sig));
|
||||
|
||||
// we emit the same error to suggest changing the arg no matter what's wrong with the arg
|
||||
let emit_main_fn_arg_err = || {
|
||||
tcx.sess.emit_err(LangStartIncorrectParam {
|
||||
param_span: decl.inputs[0].span,
|
||||
param_num: 1,
|
||||
expected_ty: expected_ty,
|
||||
found_ty: main_arg,
|
||||
});
|
||||
};
|
||||
|
||||
if let ty::FnPtr(main_fn_sig) = main_arg.kind() {
|
||||
let main_fn_inputs = main_fn_sig.inputs();
|
||||
if main_fn_inputs.iter().count() != 0 {
|
||||
emit_main_fn_arg_err();
|
||||
}
|
||||
|
||||
let output = main_fn_sig.output();
|
||||
output.map_bound(|ret_ty| {
|
||||
// if the output ty is a generic, it's probably the right one
|
||||
if !matches!(ret_ty.kind(), ty::Param(_)) {
|
||||
emit_main_fn_arg_err();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
emit_main_fn_arg_err();
|
||||
}
|
||||
}
|
||||
|
||||
// second arg is isize
|
||||
if let Some(&argc_arg) = inputs.get(1) {
|
||||
if argc_arg != tcx.types.isize {
|
||||
tcx.sess.emit_err(LangStartIncorrectParam {
|
||||
param_span: decl.inputs[1].span,
|
||||
param_num: 2,
|
||||
expected_ty: tcx.types.isize,
|
||||
found_ty: argc_arg,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// third arg is `*const *const u8`
|
||||
if let Some(&argv_arg) = inputs.get(2) {
|
||||
let mut argv_is_okay = false;
|
||||
if let ty::RawPtr(outer_ptr) = argv_arg.kind() {
|
||||
if outer_ptr.mutbl.is_not() {
|
||||
if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() {
|
||||
if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 {
|
||||
argv_is_okay = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !argv_is_okay {
|
||||
let inner_ptr_ty =
|
||||
tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
|
||||
let expected_ty =
|
||||
tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
|
||||
tcx.sess.emit_err(LangStartIncorrectParam {
|
||||
param_span: decl.inputs[2].span,
|
||||
param_num: 3,
|
||||
expected_ty,
|
||||
found_ty: argv_arg,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// fourth arg is `sigpipe: u8`
|
||||
if let Some(&sigpipe_arg) = inputs.get(3) {
|
||||
if sigpipe_arg != tcx.types.u8 {
|
||||
tcx.sess.emit_err(LangStartIncorrectParam {
|
||||
param_span: decl.inputs[3].span,
|
||||
param_num: 4,
|
||||
expected_ty: tcx.types.u8,
|
||||
found_ty: sigpipe_arg,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// output type is isize
|
||||
if fn_sig.output() != tcx.types.isize {
|
||||
tcx.sess.emit_err(LangStartIncorrectRetTy {
|
||||
ret_span: decl.output.span(),
|
||||
expected_ty: tcx.types.isize,
|
||||
found_ty: fn_sig.output(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
|
||||
self.check_for_range_as_method_call(err, expr, expr_ty, expected);
|
||||
self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
|
||||
self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
|
||||
}
|
||||
|
||||
/// Requires that the two types unify, and prints an error message if
|
||||
|
|
@ -1941,4 +1942,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.span_label(block.span, "this block is missing a tail expression");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_wrong_return_type_due_to_generic_arg(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
expr: &hir::Expr<'_>,
|
||||
checked_ty: Ty<'tcx>,
|
||||
) {
|
||||
let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
|
||||
enum CallableKind {
|
||||
Function,
|
||||
Method,
|
||||
Constructor,
|
||||
}
|
||||
let mut maybe_emit_help = |def_id: hir::def_id::DefId,
|
||||
callable: rustc_span::symbol::Ident,
|
||||
args: &[hir::Expr<'_>],
|
||||
kind: CallableKind| {
|
||||
let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
|
||||
let fn_ty = self.tcx.bound_type_of(def_id).0;
|
||||
if !fn_ty.is_fn() {
|
||||
return;
|
||||
}
|
||||
let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
|
||||
let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
|
||||
if matches!(arg.kind(), ty::Param(_))
|
||||
&& fn_sig.output().contains(arg)
|
||||
&& self.node_ty(args[arg_idx].hir_id) == checked_ty
|
||||
{
|
||||
let mut multi_span: MultiSpan = parent_expr.span.into();
|
||||
multi_span.push_span_label(
|
||||
args[arg_idx].span,
|
||||
format!(
|
||||
"this argument influences the {} of `{}`",
|
||||
if matches!(kind, CallableKind::Constructor) {
|
||||
"type"
|
||||
} else {
|
||||
"return type"
|
||||
},
|
||||
callable
|
||||
),
|
||||
);
|
||||
err.span_help(
|
||||
multi_span,
|
||||
format!(
|
||||
"the {} `{}` due to the type of the argument passed",
|
||||
match kind {
|
||||
CallableKind::Function => "return type of this call is",
|
||||
CallableKind::Method => "return type of this call is",
|
||||
CallableKind::Constructor => "type constructed contains",
|
||||
},
|
||||
checked_ty
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
match parent_expr.kind {
|
||||
hir::ExprKind::Call(fun, args) => {
|
||||
let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
|
||||
let hir::def::Res::Def(kind, def_id) = path.res else { return; };
|
||||
let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
|
||||
CallableKind::Constructor
|
||||
} else {
|
||||
CallableKind::Function
|
||||
};
|
||||
maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
|
||||
}
|
||||
hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
|
||||
let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
|
||||
maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,3 +172,36 @@ impl AddToDiagnostic for TypeMismatchFruTypo {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_lang_start_incorrect_number_params)]
|
||||
#[note(hir_typeck_lang_start_incorrect_number_params_note_expected_count)]
|
||||
#[note(hir_typeck_lang_start_expected_sig_note)]
|
||||
pub struct LangStartIncorrectNumberArgs {
|
||||
#[primary_span]
|
||||
pub params_span: Span,
|
||||
pub found_param_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_lang_start_incorrect_param)]
|
||||
pub struct LangStartIncorrectParam<'tcx> {
|
||||
#[primary_span]
|
||||
#[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
|
||||
pub param_span: Span,
|
||||
|
||||
pub param_num: usize,
|
||||
pub expected_ty: Ty<'tcx>,
|
||||
pub found_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_lang_start_incorrect_ret_ty)]
|
||||
pub struct LangStartIncorrectRetTy<'tcx> {
|
||||
#[primary_span]
|
||||
#[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
|
||||
pub ret_span: Span,
|
||||
|
||||
pub expected_ty: Ty<'tcx>,
|
||||
pub found_ty: Ty<'tcx>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||
// Named constants have to be equated with the value
|
||||
// being matched, so that's a read of the value being matched.
|
||||
//
|
||||
// FIXME: We don't actually reads for ZSTs.
|
||||
// FIXME: We don't actually reads for ZSTs.
|
||||
needs_to_be_read = true;
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -1224,9 +1224,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
GenericParamDefKind::Const { has_default } => {
|
||||
if !infer_args && has_default {
|
||||
tcx.bound_const_param_default(param.def_id)
|
||||
.subst(tcx, substs.unwrap())
|
||||
.into()
|
||||
tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
|
||||
} else {
|
||||
self.fcx.var_for_def(self.span, param)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use rustc_hir::{
|
|||
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||
};
|
||||
use rustc_hir_analysis::astconv::AstConv;
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::traits::{self, StatementAsExpression};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{
|
||||
|
|
@ -23,9 +22,9 @@ use rustc_span::source_map::Spanned;
|
|||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::NormalizeExt;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
|
||||
|
|
@ -94,7 +93,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
found: Ty<'tcx>,
|
||||
can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
|
||||
) -> bool {
|
||||
let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found)
|
||||
let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found)
|
||||
else { return false; };
|
||||
if can_satisfy(output) {
|
||||
let (sugg_call, mut applicability) = match inputs.len() {
|
||||
|
|
@ -163,99 +162,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// because the callable type must also be well-formed to be called.
|
||||
pub(in super::super) fn extract_callable_info(
|
||||
&self,
|
||||
expr: &Expr<'_>,
|
||||
found: Ty<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
|
||||
// Autoderef is useful here because sometimes we box callables, etc.
|
||||
let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| {
|
||||
match *found.kind() {
|
||||
ty::FnPtr(fn_sig) =>
|
||||
Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
|
||||
ty::FnDef(def_id, _) => {
|
||||
let fn_sig = found.fn_sig(self.tcx);
|
||||
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
|
||||
}
|
||||
ty::Closure(def_id, substs) => {
|
||||
let fn_sig = substs.as_closure().sig();
|
||||
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
|
||||
}
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
|
||||
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
|
||||
// args tuple will always be substs[1]
|
||||
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
|
||||
{
|
||||
Some((
|
||||
DefIdOrName::DefId(def_id),
|
||||
pred.kind().rebind(proj.term.ty().unwrap()),
|
||||
pred.kind().rebind(args.as_slice()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
ty::Dynamic(data, _, ty::Dyn) => {
|
||||
data.iter().find_map(|pred| {
|
||||
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
|
||||
&& Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
|
||||
// for existential projection, substs are shifted over by 1
|
||||
&& let ty::Tuple(args) = proj.substs.type_at(0).kind()
|
||||
{
|
||||
Some((
|
||||
DefIdOrName::Name("trait object"),
|
||||
pred.rebind(proj.term.ty().unwrap()),
|
||||
pred.rebind(args.as_slice()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
ty::Param(param) => {
|
||||
let def_id = self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx).def_id;
|
||||
self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
|
||||
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
|
||||
&& proj.projection_ty.self_ty() == found
|
||||
// args tuple will always be substs[1]
|
||||
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
|
||||
{
|
||||
Some((
|
||||
DefIdOrName::DefId(def_id),
|
||||
pred.kind().rebind(proj.term.ty().unwrap()),
|
||||
pred.kind().rebind(args.as_slice()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}) else { return None; };
|
||||
|
||||
let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
|
||||
let inputs = inputs
|
||||
.skip_binder()
|
||||
.iter()
|
||||
.map(|ty| {
|
||||
self.replace_bound_vars_with_fresh_vars(
|
||||
expr.span,
|
||||
infer::FnCall,
|
||||
inputs.rebind(*ty),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// We don't want to register any extra obligations, which should be
|
||||
// implied by wf, but also because that would possibly result in
|
||||
// erroneous errors later on.
|
||||
let infer::InferOk { value: output, obligations: _ } =
|
||||
self.at(&self.misc(expr.span), self.param_env).normalize(output);
|
||||
|
||||
if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
|
||||
self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
|
||||
}
|
||||
|
||||
pub fn suggest_two_fn_call(
|
||||
|
|
@ -267,9 +176,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
rhs_ty: Ty<'tcx>,
|
||||
can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
|
||||
) -> bool {
|
||||
let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty)
|
||||
let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty)
|
||||
else { return false; };
|
||||
let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty)
|
||||
let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty)
|
||||
else { return false; };
|
||||
|
||||
if can_satisfy(lhs_output_ty, rhs_output_ty) {
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>;
|
|||
pub enum Mode {
|
||||
// An expression of the form `receiver.method_name(...)`.
|
||||
// Autoderefs are performed on `receiver`, lookup is done based on the
|
||||
// `self` argument of the method, and static methods aren't considered.
|
||||
// `self` argument of the method, and static methods aren't considered.
|
||||
MethodCall,
|
||||
// An expression of the form `Type::item` or `<T>::item`.
|
||||
// No autoderefs are performed, lookup is done based on the type each
|
||||
|
|
@ -1587,11 +1587,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
let o = self.resolve_vars_if_possible(o);
|
||||
if !self.predicate_may_hold(&o) {
|
||||
result = ProbeResult::NoMatch;
|
||||
possibly_unsatisfied_predicates.push((
|
||||
o.predicate,
|
||||
None,
|
||||
Some(o.cause),
|
||||
));
|
||||
let parent_o = o.clone();
|
||||
let implied_obligations =
|
||||
traits::elaborate_obligations(self.tcx, vec![o]);
|
||||
for o in implied_obligations {
|
||||
let parent = if o == parent_o {
|
||||
None
|
||||
} else {
|
||||
if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
|
||||
== self.tcx.lang_items().sized_trait()
|
||||
{
|
||||
// We don't care to talk about implicit `Sized` bounds.
|
||||
continue;
|
||||
}
|
||||
Some(parent_o.predicate)
|
||||
};
|
||||
if !self.predicate_may_hold(&o) {
|
||||
possibly_unsatisfied_predicates.push((
|
||||
o.predicate,
|
||||
parent,
|
||||
Some(o.cause),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -505,19 +505,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
|
||||
if let Some(g) = kind.generics() {
|
||||
let key = (
|
||||
g.tail_span_for_predicate_suggestion(),
|
||||
g.add_where_or_trailing_comma(),
|
||||
);
|
||||
type_params
|
||||
.entry(key)
|
||||
.or_insert_with(FxHashSet::default)
|
||||
.insert(obligation.to_owned());
|
||||
}
|
||||
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
|
||||
&& let Some(g) = kind.generics()
|
||||
{
|
||||
let key = (
|
||||
g.tail_span_for_predicate_suggestion(),
|
||||
g.add_where_or_trailing_comma(),
|
||||
);
|
||||
type_params
|
||||
.entry(key)
|
||||
.or_insert_with(FxHashSet::default)
|
||||
.insert(obligation.to_owned());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
|
||||
let msg = format!(
|
||||
|
|
@ -692,7 +694,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
"auto trait is invoked with no method error, but no error reported?",
|
||||
);
|
||||
}
|
||||
Some(_) => unreachable!(),
|
||||
Some(Node::Item(hir::Item {
|
||||
ident, kind: hir::ItemKind::Trait(..), ..
|
||||
})) => {
|
||||
skip_list.insert(p);
|
||||
let entry = spanned_predicates.entry(ident.span);
|
||||
let entry = entry.or_insert_with(|| {
|
||||
(FxHashSet::default(), FxHashSet::default(), Vec::new())
|
||||
});
|
||||
entry.0.insert(cause.span);
|
||||
entry.1.insert((ident.span, ""));
|
||||
entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
|
||||
entry.2.push(p);
|
||||
}
|
||||
Some(node) => unreachable!("encountered `{node:?}`"),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
|
|
@ -719,19 +734,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
unsatisfied_bounds = true;
|
||||
}
|
||||
|
||||
let mut suggested_bounds = FxHashSet::default();
|
||||
// The requirements that didn't have an `impl` span to show.
|
||||
let mut bound_list = unsatisfied_predicates
|
||||
.iter()
|
||||
.filter_map(|(pred, parent_pred, _cause)| {
|
||||
let mut suggested = false;
|
||||
format_pred(*pred).map(|(p, self_ty)| {
|
||||
collect_type_param_suggestions(self_ty, *pred, &p);
|
||||
if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
|
||||
// We don't suggest `PartialEq` when we already suggest `Eq`.
|
||||
} else if !suggested_bounds.contains(pred) {
|
||||
if collect_type_param_suggestions(self_ty, *pred, &p) {
|
||||
suggested = true;
|
||||
suggested_bounds.insert(pred);
|
||||
}
|
||||
}
|
||||
(
|
||||
match parent_pred {
|
||||
None => format!("`{}`", &p),
|
||||
Some(parent_pred) => match format_pred(*parent_pred) {
|
||||
None => format!("`{}`", &p),
|
||||
Some((parent_p, _)) => {
|
||||
collect_type_param_suggestions(self_ty, *parent_pred, &p);
|
||||
if !suggested
|
||||
&& !suggested_bounds.contains(pred)
|
||||
&& !suggested_bounds.contains(parent_pred)
|
||||
{
|
||||
if collect_type_param_suggestions(
|
||||
self_ty,
|
||||
*parent_pred,
|
||||
&p,
|
||||
) {
|
||||
suggested_bounds.insert(pred);
|
||||
}
|
||||
}
|
||||
format!("`{}`\nwhich is required by `{}`", p, parent_p)
|
||||
}
|
||||
},
|
||||
|
|
@ -1037,7 +1072,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// the impl, if local to crate (item may be defaulted), else nothing.
|
||||
let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
|
||||
let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
|
||||
self.associated_value(impl_trait_ref.def_id, item_name)
|
||||
self.associated_value(impl_trait_ref.skip_binder().def_id, item_name)
|
||||
}) else {
|
||||
continue;
|
||||
};
|
||||
|
|
@ -1055,7 +1090,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let insertion = match self.tcx.impl_trait_ref(impl_did) {
|
||||
None => String::new(),
|
||||
Some(trait_ref) => {
|
||||
format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
|
||||
format!(
|
||||
" of the trait `{}`",
|
||||
self.tcx.def_path_str(trait_ref.skip_binder().def_id)
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1086,7 +1124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
if let Some(sugg_span) = sugg_span
|
||||
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
|
||||
let path = self.tcx.def_path_str(trait_ref.def_id);
|
||||
let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
|
||||
|
||||
let ty = match item.kind {
|
||||
ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
|
||||
|
|
@ -2581,7 +2619,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
|
||||
})
|
||||
.any(|imp_did| {
|
||||
let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
|
||||
let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
|
||||
let imp_simp =
|
||||
simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
|
||||
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
|
||||
|
|
@ -2662,8 +2700,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
found: Ty<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
|
||||
else { return false; };
|
||||
let Some((_def_id_or_name, output, _inputs)) =
|
||||
self.extract_callable_info(found) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if !self.can_coerce(output, expected) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1782,9 +1782,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
// like when you have two references but one is `usize` and the other
|
||||
// is `f32`. In those cases we still want to show the `note`. If the
|
||||
// value from `ef` is `Infer(_)`, then we ignore it.
|
||||
if !ef.expected.is_ty_infer() {
|
||||
if !ef.expected.is_ty_or_numeric_infer() {
|
||||
ef.expected != values.expected
|
||||
} else if !ef.found.is_ty_infer() {
|
||||
} else if !ef.found.is_ty_or_numeric_infer() {
|
||||
ef.found != values.found
|
||||
} else {
|
||||
false
|
||||
|
|
@ -1923,6 +1923,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
(ty::Tuple(fields), _) => {
|
||||
self.emit_tuple_wrap_err(&mut err, span, found, fields)
|
||||
}
|
||||
// If a byte was expected and the found expression is a char literal
|
||||
// containing a single ASCII character, perhaps the user meant to write `b'c'` to
|
||||
// specify a byte literal
|
||||
(ty::Uint(ty::UintTy::U8), ty::Char) => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
|
||||
&& code.chars().next().map_or(false, |c| c.is_ascii())
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"if you meant to write a byte literal, prefix with `b`",
|
||||
format!("b'{}'", escape_literal(code)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
// If a character was expected and the found expression is a string literal
|
||||
// containing a single character, perhaps the user meant to write `'c'` to
|
||||
// specify a character literal (issue #92479)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ impl InferenceDiagnosticsData {
|
|||
}
|
||||
|
||||
fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str {
|
||||
if in_type.is_ty_infer() {
|
||||
if in_type.is_ty_or_numeric_infer() {
|
||||
""
|
||||
} else if self.name == "_" {
|
||||
// FIXME: Consider specializing this message if there is a single `_`
|
||||
|
|
@ -195,12 +195,12 @@ fn ty_to_string<'tcx>(
|
|||
// invalid pseudo-syntax, we want the `fn`-pointer output instead.
|
||||
(ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
|
||||
(_, Some(def_id))
|
||||
if ty.is_ty_infer()
|
||||
if ty.is_ty_or_numeric_infer()
|
||||
&& infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) =>
|
||||
{
|
||||
"Vec<_>".to_string()
|
||||
}
|
||||
_ if ty.is_ty_infer() => "/* Type */".to_string(),
|
||||
_ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(),
|
||||
// FIXME: The same thing for closures, but this only works when the closure
|
||||
// does not capture anything.
|
||||
//
|
||||
|
|
@ -680,7 +680,7 @@ impl<'tcx> InferSourceKind<'tcx> {
|
|||
| InferSourceKind::ClosureReturn { ty, .. } => {
|
||||
if ty.is_closure() {
|
||||
("closure", closure_as_fn_str(infcx, ty))
|
||||
} else if !ty.is_ty_infer() {
|
||||
} else if !ty.is_ty_or_numeric_infer() {
|
||||
("normal", ty_to_string(infcx, ty, None))
|
||||
} else {
|
||||
("other", String::new())
|
||||
|
|
@ -813,7 +813,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
|||
self.attempt += 1;
|
||||
if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source
|
||||
&& let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind
|
||||
&& ty.is_ty_infer()
|
||||
&& ty.is_ty_or_numeric_infer()
|
||||
{
|
||||
// Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
|
||||
// `let x: _ = iter.collect();`, as this is a very common case.
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
.impl_trait_ref(impl_def_id)
|
||||
else { return; };
|
||||
let trait_substs = trait_ref
|
||||
.subst_identity()
|
||||
// Replace the explicit self type with `Self` for better suggestion rendering
|
||||
.with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
|
||||
.substs;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use smallvec::smallvec;
|
||||
|
||||
use crate::infer::outlives::components::{push_outlives_components, Component};
|
||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
||||
use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
@ -145,16 +145,28 @@ impl<'tcx> Elaborator<'tcx> {
|
|||
// Get predicates declared on the trait.
|
||||
let predicates = tcx.super_predicates_of(data.def_id());
|
||||
|
||||
let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
|
||||
let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
|
||||
// when parent predicate is non-const, elaborate it to non-const predicates.
|
||||
if data.constness == ty::BoundConstness::NotConst {
|
||||
pred = pred.without_const(tcx);
|
||||
}
|
||||
|
||||
let cause = obligation.cause.clone().derived_cause(
|
||||
bound_predicate.rebind(data),
|
||||
|derived| {
|
||||
traits::ImplDerivedObligation(Box::new(
|
||||
traits::ImplDerivedObligationCause {
|
||||
derived,
|
||||
impl_def_id: data.def_id(),
|
||||
span,
|
||||
},
|
||||
))
|
||||
},
|
||||
);
|
||||
predicate_obligation(
|
||||
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
cause,
|
||||
)
|
||||
});
|
||||
debug!(?data, ?obligations, "super_predicates");
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ rustc_plugin_impl = { path = "../rustc_plugin_impl" }
|
|||
rustc_privacy = { path = "../rustc_privacy" }
|
||||
rustc_query_impl = { path = "../rustc_query_impl" }
|
||||
rustc_resolve = { path = "../rustc_resolve" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||
rustc_ty_utils = { path = "../rustc_ty_utils" }
|
||||
|
||||
|
|
|
|||
|
|
@ -87,3 +87,7 @@ pub struct FailedWritingFile<'a> {
|
|||
pub path: &'a Path,
|
||||
pub error: io::Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(interface_proc_macro_crate_panic_abort)]
|
||||
pub struct ProcMacroCratePanicAbort;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use crate::errors::{
|
||||
CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier,
|
||||
GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate,
|
||||
MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError,
|
||||
MixedProcMacroCrate, OutDirError, ProcMacroCratePanicAbort, ProcMacroDocWithoutArg,
|
||||
TempsDirError,
|
||||
};
|
||||
use crate::interface::{Compiler, Result};
|
||||
use crate::proc_macro_decls;
|
||||
|
|
@ -36,6 +37,7 @@ use rustc_session::search_paths::PathKind;
|
|||
use rustc_session::{Limit, Session};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::FileName;
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use std::any::Any;
|
||||
|
|
@ -380,6 +382,10 @@ pub fn configure_and_expand(
|
|||
}
|
||||
}
|
||||
|
||||
if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
|
||||
sess.emit_warning(ProcMacroCratePanicAbort);
|
||||
}
|
||||
|
||||
// For backwards compatibility, we don't try to run proc macro injection
|
||||
// if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
|
||||
// specified. This should only affect users who manually invoke 'rustdoc', as
|
||||
|
|
@ -817,23 +823,26 @@ pub fn create_global_ctxt<'tcx>(
|
|||
lint_store,
|
||||
arena,
|
||||
hir_arena,
|
||||
untracked_resolutions,
|
||||
untracked,
|
||||
krate,
|
||||
dep_graph,
|
||||
queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
|
||||
queries.as_dyn(),
|
||||
rustc_query_impl::query_callbacks(arena),
|
||||
crate_name,
|
||||
outputs,
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
let mut qcx = QueryContext { gcx };
|
||||
qcx.enter(|tcx| {
|
||||
tcx.feed_unit_query()
|
||||
.resolver_for_lowering(tcx.arena.alloc(Steal::new(untracked_resolver_for_lowering)))
|
||||
let feed = tcx.feed_unit_query();
|
||||
feed.resolver_for_lowering(
|
||||
tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))),
|
||||
);
|
||||
feed.resolutions(tcx.arena.alloc(untracked_resolutions));
|
||||
feed.output_filenames(tcx.arena.alloc(std::sync::Arc::new(outputs)));
|
||||
feed.features_query(sess.features_untracked());
|
||||
let feed = tcx.feed_local_crate();
|
||||
feed.crate_name(crate_name);
|
||||
});
|
||||
qcx
|
||||
}
|
||||
|
|
|
|||
|
|
@ -748,6 +748,7 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(link_only, true);
|
||||
tracked!(llvm_plugins, vec![String::from("plugin_name")]);
|
||||
tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
|
||||
tracked!(log_backtrace, Some("filter".to_string()));
|
||||
tracked!(maximal_hir_to_mir_coverage, true);
|
||||
tracked!(merge_functions, Some(MergeFunctions::Disabled));
|
||||
tracked!(mir_emit_retag, true);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
}
|
||||
|
||||
fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
|
||||
if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
|
||||
if !tcx.features().enabled(sym::lint_reasons) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1105,6 +1105,7 @@ impl UnusedDelimLint for UnusedBraces {
|
|||
|| matches!(expr.kind, ast::ExprKind::Lit(_)))
|
||||
&& !cx.sess().source_map().is_multiline(value.span)
|
||||
&& value.attrs.is_empty()
|
||||
&& !expr.span.from_expansion()
|
||||
&& !value.span.from_expansion()
|
||||
&& !inner.span.from_expansion()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4033,10 +4033,10 @@ declare_lint! {
|
|||
///
|
||||
/// This can be used to implement an unsound API if used incorrectly.
|
||||
pub IMPLIED_BOUNDS_ENTAILMENT,
|
||||
Warn,
|
||||
Deny,
|
||||
"impl method assumes more implied bounds than its corresponding trait method",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>",
|
||||
reason: FutureIncompatibilityReason::FutureReleaseError,
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
tracing = "0.1.28"
|
||||
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
|
||||
tracing-tree = "0.2.0"
|
||||
tracing-core = "0.1.28"
|
||||
|
||||
[dev-dependencies]
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
|
|
|||
|
|
@ -45,16 +45,34 @@
|
|||
use std::env::{self, VarError};
|
||||
use std::fmt::{self, Display};
|
||||
use std::io::{self, IsTerminal};
|
||||
use tracing_core::{Event, Subscriber};
|
||||
use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
|
||||
use tracing_subscriber::fmt::{
|
||||
format::{self, FormatEvent, FormatFields},
|
||||
FmtContext,
|
||||
};
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
|
||||
pub fn init_rustc_env_logger() -> Result<(), Error> {
|
||||
init_env_logger("RUSTC_LOG")
|
||||
init_rustc_env_logger_with_backtrace_option(&None)
|
||||
}
|
||||
|
||||
pub fn init_rustc_env_logger_with_backtrace_option(
|
||||
backtrace_target: &Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
init_env_logger_with_backtrace_option("RUSTC_LOG", backtrace_target)
|
||||
}
|
||||
|
||||
/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
|
||||
/// other than `RUSTC_LOG`.
|
||||
pub fn init_env_logger(env: &str) -> Result<(), Error> {
|
||||
init_env_logger_with_backtrace_option(env, &None)
|
||||
}
|
||||
|
||||
pub fn init_env_logger_with_backtrace_option(
|
||||
env: &str,
|
||||
backtrace_target: &Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
let filter = match env::var(env) {
|
||||
Ok(env) => EnvFilter::new(env),
|
||||
_ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
|
||||
|
|
@ -88,11 +106,47 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> {
|
|||
let layer = layer.with_thread_ids(true).with_thread_names(true);
|
||||
|
||||
let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
|
||||
tracing::subscriber::set_global_default(subscriber).unwrap();
|
||||
match backtrace_target {
|
||||
Some(str) => {
|
||||
let fmt_layer = tracing_subscriber::fmt::layer()
|
||||
.with_writer(io::stderr)
|
||||
.without_time()
|
||||
.event_format(BacktraceFormatter { backtrace_target: str.to_string() });
|
||||
let subscriber = subscriber.with(fmt_layer);
|
||||
tracing::subscriber::set_global_default(subscriber).unwrap();
|
||||
}
|
||||
None => {
|
||||
tracing::subscriber::set_global_default(subscriber).unwrap();
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct BacktraceFormatter {
|
||||
backtrace_target: String,
|
||||
}
|
||||
|
||||
impl<S, N> FormatEvent<S, N> for BacktraceFormatter
|
||||
where
|
||||
S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
|
||||
N: for<'a> FormatFields<'a> + 'static,
|
||||
{
|
||||
fn format_event(
|
||||
&self,
|
||||
_ctx: &FmtContext<'_, S, N>,
|
||||
mut writer: format::Writer<'_>,
|
||||
event: &Event<'_>,
|
||||
) -> fmt::Result {
|
||||
let target = event.metadata().target();
|
||||
if !target.contains(&self.backtrace_target) {
|
||||
return Ok(());
|
||||
}
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
writeln!(writer, "stack backtrace: \n{:?}", backtrace)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stdout_isatty() -> bool {
|
||||
io::stdout().is_terminal()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1555,7 +1555,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
self.tables.impl_defaultness.set(def_id.index, *defaultness);
|
||||
self.tables.constness.set(def_id.index, *constness);
|
||||
|
||||
let trait_ref = self.tcx.impl_trait_ref(def_id);
|
||||
let trait_ref = self.tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::skip_binder);
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
let trait_def = self.tcx.trait_def(trait_ref.def_id);
|
||||
if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) {
|
||||
|
|
@ -1899,6 +1899,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
for id in tcx.hir().items() {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
|
||||
let trait_ref = trait_ref.subst_identity();
|
||||
|
||||
let simplified_self_ty = fast_reject::simplify_type(
|
||||
self.tcx,
|
||||
trait_ref.self_ty(),
|
||||
|
|
|
|||
|
|
@ -359,8 +359,8 @@ define_tables! {
|
|||
variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
|
||||
fn_sig: Table<DefIndex, LazyValue<ty::PolyFnSig<'static>>>,
|
||||
codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
|
||||
impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
|
||||
const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>,
|
||||
impl_trait_ref: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::TraitRef<'static>>>>,
|
||||
const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<rustc_middle::ty::Const<'static>>>>,
|
||||
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
|
||||
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
||||
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,12 @@ macro_rules! arena_types {
|
|||
[decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
|
||||
[decode] borrowck_result:
|
||||
rustc_middle::mir::BorrowCheckResult<'tcx>,
|
||||
[] resolver: rustc_data_structures::steal::Steal<rustc_middle::ty::ResolverAstLowering>,
|
||||
[] resolver: rustc_data_structures::steal::Steal<(
|
||||
rustc_middle::ty::ResolverAstLowering,
|
||||
rustc_data_structures::sync::Lrc<rustc_ast::Crate>,
|
||||
)>,
|
||||
[] output_filenames: std::sync::Arc<rustc_session::config::OutputFilenames>,
|
||||
[] resolutions: rustc_middle::ty::ResolverGlobalCtxt,
|
||||
[decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
|
||||
[decode] code_region: rustc_middle::mir::coverage::CodeRegion,
|
||||
[] const_allocs: rustc_middle::mir::interpret::Allocation,
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> {
|
||||
self.impl_trait_ref(def_id)
|
||||
.map(|t| t.subst_identity())
|
||||
.map(ImplSubject::Trait)
|
||||
.unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt {
|
||||
eval_always
|
||||
feedable
|
||||
no_hash
|
||||
desc { "getting the resolver outputs" }
|
||||
}
|
||||
|
||||
query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
|
||||
query resolver_for_lowering(_: ()) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> {
|
||||
feedable
|
||||
no_hash
|
||||
desc { "getting the resolver for lowering" }
|
||||
|
|
@ -142,7 +142,7 @@ rustc_queries! {
|
|||
|
||||
/// Given the def_id of a const-generic parameter, computes the associated default const
|
||||
/// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
|
||||
query const_param_default(param: DefId) -> ty::Const<'tcx> {
|
||||
query const_param_default(param: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
|
||||
desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param) }
|
||||
cache_on_disk_if { param.is_local() }
|
||||
separate_provide_extern
|
||||
|
|
@ -737,7 +737,7 @@ rustc_queries! {
|
|||
|
||||
/// Given an `impl_id`, return the trait it implements.
|
||||
/// Return `None` if this is an inherent impl.
|
||||
query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
|
||||
query impl_trait_ref(impl_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
|
||||
desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
|
||||
cache_on_disk_if { impl_id.is_local() }
|
||||
separate_provide_extern
|
||||
|
|
@ -1673,7 +1673,7 @@ rustc_queries! {
|
|||
|
||||
/// Gets the name of the crate.
|
||||
query crate_name(_: CrateNum) -> Symbol {
|
||||
eval_always
|
||||
feedable
|
||||
desc { "fetching what a crate is named" }
|
||||
separate_provide_extern
|
||||
}
|
||||
|
|
@ -1857,7 +1857,7 @@ rustc_queries! {
|
|||
/// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
|
||||
/// has been destroyed.
|
||||
query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
|
||||
eval_always
|
||||
feedable
|
||||
desc { "getting output filenames" }
|
||||
}
|
||||
|
||||
|
|
@ -2041,7 +2041,7 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
query features_query(_: ()) -> &'tcx rustc_feature::Features {
|
||||
eval_always
|
||||
feedable
|
||||
desc { "looking up enabled feature gates" }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> Const<'_> {
|
||||
pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Const<'_>> {
|
||||
let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) {
|
||||
hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Const { default: Some(ac), .. },
|
||||
|
|
@ -250,5 +250,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> Const<'_> {
|
|||
"`const_param_default` expected a generic parameter with a constant"
|
||||
),
|
||||
};
|
||||
Const::from_anon_const(tcx, default_def_id)
|
||||
ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ use rustc_macros::HashStable;
|
|||
use rustc_query_system::dep_graph::DepNodeIndex;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
||||
use rustc_session::config::{CrateType, OutputFilenames};
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_session::cstore::{CrateStoreDyn, Untracked};
|
||||
use rustc_session::lint::Lint;
|
||||
use rustc_session::Limit;
|
||||
|
|
@ -74,7 +74,6 @@ use std::hash::{Hash, Hasher};
|
|||
use std::iter;
|
||||
use std::mem;
|
||||
use std::ops::{Bound, Deref};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
|
||||
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
|
||||
|
|
@ -363,6 +362,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn feed_unit_query(self) -> TyCtxtFeed<'tcx, ()> {
|
||||
TyCtxtFeed { tcx: self, key: () }
|
||||
}
|
||||
pub fn feed_local_crate(self) -> TyCtxtFeed<'tcx, CrateNum> {
|
||||
TyCtxtFeed { tcx: self, key: LOCAL_CRATE }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
|
||||
|
|
@ -428,11 +430,6 @@ pub struct GlobalCtxt<'tcx> {
|
|||
pub consts: CommonConsts<'tcx>,
|
||||
|
||||
untracked: Untracked,
|
||||
/// Output of the resolver.
|
||||
pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt,
|
||||
/// The entire crate as AST. This field serves as the input for the hir_crate query,
|
||||
/// which lowers it from AST to HIR. It must not be read or used by anything else.
|
||||
pub untracked_crate: Steal<Lrc<ast::Crate>>,
|
||||
|
||||
/// This provides access to the incremental compilation on-disk cache for query results.
|
||||
/// Do not access this directly. It is only meant to be used by
|
||||
|
|
@ -457,17 +454,11 @@ pub struct GlobalCtxt<'tcx> {
|
|||
/// Merge this with `selection_cache`?
|
||||
pub evaluation_cache: traits::EvaluationCache<'tcx>,
|
||||
|
||||
/// The definite name of the current crate after taking into account
|
||||
/// attributes, commandline parameters, etc.
|
||||
crate_name: Symbol,
|
||||
|
||||
/// Data layout specification for the current target.
|
||||
pub data_layout: TargetDataLayout,
|
||||
|
||||
/// Stores memory for globals (statics/consts).
|
||||
pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
|
||||
|
||||
output_filenames: Arc<OutputFilenames>,
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
|
|
@ -592,15 +583,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
|
||||
arena: &'tcx WorkerLocal<Arena<'tcx>>,
|
||||
hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
|
||||
untracked_resolutions: ty::ResolverGlobalCtxt,
|
||||
untracked: Untracked,
|
||||
krate: Lrc<ast::Crate>,
|
||||
dep_graph: DepGraph,
|
||||
on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
|
||||
queries: &'tcx dyn query::QueryEngine<'tcx>,
|
||||
query_kinds: &'tcx [DepKindStruct<'tcx>],
|
||||
crate_name: Symbol,
|
||||
output_filenames: OutputFilenames,
|
||||
) -> GlobalCtxt<'tcx> {
|
||||
let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| {
|
||||
s.emit_fatal(err);
|
||||
|
|
@ -622,8 +609,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
lifetimes: common_lifetimes,
|
||||
consts: common_consts,
|
||||
untracked,
|
||||
untracked_resolutions,
|
||||
untracked_crate: Steal::new(krate),
|
||||
on_disk_cache,
|
||||
queries,
|
||||
query_caches: query::QueryCaches::default(),
|
||||
|
|
@ -632,10 +617,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pred_rcache: Default::default(),
|
||||
selection_cache: Default::default(),
|
||||
evaluation_cache: Default::default(),
|
||||
crate_name,
|
||||
data_layout,
|
||||
alloc_map: Lock::new(interpret::AllocMap::new()),
|
||||
output_filenames: Arc::new(output_filenames),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -810,7 +793,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
// statements within the query system and we'd run into endless
|
||||
// recursion otherwise.
|
||||
let (crate_name, stable_crate_id) = if def_id.is_local() {
|
||||
(self.crate_name, self.sess.local_stable_crate_id())
|
||||
(self.crate_name(LOCAL_CRATE), self.sess.local_stable_crate_id())
|
||||
} else {
|
||||
let cstore = &*self.untracked.cstore;
|
||||
(cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate))
|
||||
|
|
@ -2407,13 +2390,8 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
|
|||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers) {
|
||||
providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
|
||||
providers.module_reexports =
|
||||
|tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
|
||||
providers.crate_name = |tcx, id| {
|
||||
assert_eq!(id, LOCAL_CRATE);
|
||||
tcx.crate_name
|
||||
};
|
||||
providers.maybe_unused_trait_imports =
|
||||
|tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
|
||||
providers.maybe_unused_extern_crates =
|
||||
|
|
@ -2424,8 +2402,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
|||
|
||||
providers.extern_mod_stmt_cnum =
|
||||
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
|
||||
providers.output_filenames = |tcx, ()| &tcx.output_filenames;
|
||||
providers.features_query = |tcx, ()| tcx.sess.features_untracked();
|
||||
providers.is_panic_runtime = |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ impl GenericParamDef {
|
|||
Some(tcx.bound_type_of(self.def_id).map_bound(|t| t.into()))
|
||||
}
|
||||
GenericParamDefKind::Const { has_default } if has_default => {
|
||||
Some(tcx.bound_const_param_default(self.def_id).map_bound(|c| c.into()))
|
||||
Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2187,8 +2187,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
) -> Option<ImplOverlapKind> {
|
||||
// If either trait impl references an error, they're allowed to overlap,
|
||||
// as one of them essentially doesn't exist.
|
||||
if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.references_error())
|
||||
|| self.impl_trait_ref(def_id2).map_or(false, |tr| tr.references_error())
|
||||
if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.subst_identity().references_error())
|
||||
|| self
|
||||
.impl_trait_ref(def_id2)
|
||||
.map_or(false, |tr| tr.subst_identity().references_error())
|
||||
{
|
||||
return Some(ImplOverlapKind::Permitted { marker: false });
|
||||
}
|
||||
|
|
@ -2218,7 +2220,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let is_marker_overlap = {
|
||||
let is_marker_impl = |def_id: DefId| -> bool {
|
||||
let trait_ref = self.impl_trait_ref(def_id);
|
||||
trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker)
|
||||
trait_ref.map_or(false, |tr| self.trait_def(tr.skip_binder().def_id).is_marker)
|
||||
};
|
||||
is_marker_impl(def_id1) && is_marker_impl(def_id2)
|
||||
};
|
||||
|
|
@ -2364,7 +2366,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
|
||||
/// If it implements no trait, returns `None`.
|
||||
pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
|
||||
self.impl_trait_ref(def_id).map(|tr| tr.def_id)
|
||||
self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
|
||||
}
|
||||
|
||||
/// If the given `DefId` describes an item belonging to a trait,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
|
|||
type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
|
||||
}
|
||||
|
||||
impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<T> {
|
||||
type Value<'tcx> = ty::EarlyBinder<T::Value<'tcx>>;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! trivially_parameterized_over_tcx {
|
||||
($($ty:ty),+ $(,)?) => {
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ pub trait Printer<'tcx>: Sized {
|
|||
DefPathData::Impl => {
|
||||
let generics = self.tcx().generics_of(def_id);
|
||||
let self_ty = self.tcx().bound_type_of(def_id);
|
||||
let impl_trait_ref = self.tcx().bound_impl_trait_ref(def_id);
|
||||
let impl_trait_ref = self.tcx().impl_trait_ref(def_id);
|
||||
let (self_ty, impl_trait_ref) = if substs.len() >= generics.count() {
|
||||
(
|
||||
self_ty.subst(self.tcx(), substs),
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
|
|||
use crate::ty::visit::ValidateBoundVars;
|
||||
use crate::ty::InferTy::*;
|
||||
use crate::ty::{
|
||||
self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitor,
|
||||
self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
|
||||
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
||||
};
|
||||
use crate::ty::{List, ParamEnv};
|
||||
use hir::def::DefKind;
|
||||
|
|
@ -1106,6 +1106,17 @@ impl<'tcx, T> Binder<'tcx, T> {
|
|||
if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
|
||||
}
|
||||
|
||||
pub fn no_bound_vars_ignoring_escaping(self, tcx: TyCtxt<'tcx>) -> Option<T>
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
if !self.0.has_escaping_bound_vars() {
|
||||
Some(self.skip_binder())
|
||||
} else {
|
||||
self.0.try_fold_with(&mut SkipBindersAt { index: ty::INNERMOST, tcx }).ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits the contents into two things that share the same binder
|
||||
/// level as the original, returning two distinct binders.
|
||||
///
|
||||
|
|
@ -1135,6 +1146,81 @@ impl<'tcx, T: IntoIterator> Binder<'tcx, T> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SkipBindersAt<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
index: ty::DebruijnIndex,
|
||||
}
|
||||
|
||||
impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
|
||||
type Error = ();
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
|
||||
where
|
||||
T: ty::TypeFoldable<'tcx>,
|
||||
{
|
||||
self.index.shift_in(1);
|
||||
let value = t.try_map_bound(|t| t.try_fold_with(self));
|
||||
self.index.shift_out(1);
|
||||
value
|
||||
}
|
||||
|
||||
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
||||
if !ty.has_escaping_bound_vars() {
|
||||
Ok(ty)
|
||||
} else if let ty::Bound(index, bv) = *ty.kind() {
|
||||
if index == self.index {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(self.tcx().mk_ty(ty::Bound(index.shifted_out(1), bv)))
|
||||
}
|
||||
} else {
|
||||
ty.try_super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
|
||||
if !r.has_escaping_bound_vars() {
|
||||
Ok(r)
|
||||
} else if let ty::ReLateBound(index, bv) = r.kind() {
|
||||
if index == self.index {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(self.tcx().mk_region(ty::ReLateBound(index.shifted_out(1), bv)))
|
||||
}
|
||||
} else {
|
||||
r.try_super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
|
||||
if !ct.has_escaping_bound_vars() {
|
||||
Ok(ct)
|
||||
} else if let ty::ConstKind::Bound(index, bv) = ct.kind() {
|
||||
if index == self.index {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(self.tcx().mk_const(
|
||||
ty::ConstKind::Bound(index.shifted_out(1), bv),
|
||||
ct.ty().try_fold_with(self)?,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
ct.try_super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_fold_predicate(
|
||||
&mut self,
|
||||
p: ty::Predicate<'tcx>,
|
||||
) -> Result<ty::Predicate<'tcx>, Self::Error> {
|
||||
if !p.has_escaping_bound_vars() { Ok(p) } else { p.try_super_fold_with(self) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the projection of an associated type.
|
||||
///
|
||||
/// For a projection, this would be `<Ty as Trait<...>>::N`.
|
||||
|
|
@ -1686,7 +1772,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_ty_infer(self) -> bool {
|
||||
pub fn is_ty_or_numeric_infer(self) -> bool {
|
||||
matches!(self.kind(), Infer(_))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ impl<'tcx> GenericArg<'tcx> {
|
|||
pub fn is_non_region_infer(self) -> bool {
|
||||
match self.unpack() {
|
||||
GenericArgKind::Lifetime(_) => false,
|
||||
GenericArgKind::Type(ty) => ty.is_ty_infer(),
|
||||
GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(),
|
||||
GenericArgKind::Const(ct) => ct.is_ct_infer(),
|
||||
}
|
||||
}
|
||||
|
|
@ -713,6 +713,10 @@ impl<'tcx, T: TypeFoldable<'tcx>> ty::EarlyBinder<T> {
|
|||
let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
|
||||
self.0.fold_with(&mut folder)
|
||||
}
|
||||
|
||||
pub fn subst_identity(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ pub struct TypeckResults<'tcx> {
|
|||
pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
|
||||
|
||||
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
|
||||
/// as `&[u8]`, depending on the pattern in which they are used.
|
||||
/// as `&[u8]`, depending on the pattern in which they are used.
|
||||
/// This hashset records all instances where we behave
|
||||
/// like this to allow `const_to_pat` to reliably handle this situation.
|
||||
pub treat_byte_string_as_slice: ItemLocalSet,
|
||||
|
|
|
|||
|
|
@ -652,13 +652,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
ty::EarlyBinder(self.fn_sig(def_id))
|
||||
}
|
||||
|
||||
pub fn bound_impl_trait_ref(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
|
||||
self.impl_trait_ref(def_id).map(|i| ty::EarlyBinder(i))
|
||||
}
|
||||
|
||||
pub fn bound_explicit_item_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
|
|
@ -673,10 +666,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
ty::EarlyBinder(self.item_bounds(def_id))
|
||||
}
|
||||
|
||||
pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
|
||||
ty::EarlyBinder(self.const_param_default(def_id))
|
||||
}
|
||||
|
||||
pub fn bound_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
|
|
|
|||
|
|
@ -94,6 +94,18 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
|
||||
ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
|
||||
ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle))
|
||||
}
|
||||
}
|
||||
|
||||
// item_and_field_ids should form a cycle where each field contains the
|
||||
// type in the next element in the list
|
||||
pub fn recursive_type_error(
|
||||
|
|
|
|||
|
|
@ -1352,6 +1352,8 @@ fn create_mono_items_for_default_impls<'tcx>(
|
|||
);
|
||||
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
|
||||
let trait_ref = trait_ref.subst_identity();
|
||||
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
|
||||
let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ impl<'a> StringReader<'a> {
|
|||
/// preceded by whitespace.
|
||||
fn next_token(&mut self) -> (Token, bool) {
|
||||
let mut preceded_by_whitespace = false;
|
||||
|
||||
let mut swallow_next_invalid = 0;
|
||||
// Skip trivial (whitespace & comments) tokens
|
||||
loop {
|
||||
let token = self.cursor.advance_token();
|
||||
|
|
@ -232,19 +232,34 @@ impl<'a> StringReader<'a> {
|
|||
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
|
||||
|
||||
rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
|
||||
let c = self.str_from(start).chars().next().unwrap();
|
||||
// Don't emit diagnostics for sequences of the same invalid token
|
||||
if swallow_next_invalid > 0 {
|
||||
swallow_next_invalid -= 1;
|
||||
continue;
|
||||
}
|
||||
let mut it = self.str_from_to_end(start).chars();
|
||||
let c = it.next().unwrap();
|
||||
let repeats = it.take_while(|c1| *c1 == c).count();
|
||||
let mut err =
|
||||
self.struct_err_span_char(start, self.pos, "unknown start of token", c);
|
||||
self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c);
|
||||
// FIXME: the lexer could be used to turn the ASCII version of unicode
|
||||
// homoglyphs, instead of keeping a table in `check_for_substitution`into the
|
||||
// token. Ideally, this should be inside `rustc_lexer`. However, we should
|
||||
// first remove compound tokens like `<<` from `rustc_lexer`, and then add
|
||||
// fancier error recovery to it, as there will be less overall work to do this
|
||||
// way.
|
||||
let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
|
||||
let token = unicode_chars::check_for_substitution(self, start, c, &mut err, repeats+1);
|
||||
if c == '\x00' {
|
||||
err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
|
||||
}
|
||||
if repeats > 0 {
|
||||
if repeats == 1 {
|
||||
err.note(format!("character appears once more"));
|
||||
} else {
|
||||
err.note(format!("character appears {repeats} more times"));
|
||||
}
|
||||
swallow_next_invalid = repeats;
|
||||
}
|
||||
err.emit();
|
||||
if let Some(token) = token {
|
||||
token
|
||||
|
|
@ -486,6 +501,11 @@ impl<'a> StringReader<'a> {
|
|||
&self.src[self.src_index(start)..self.src_index(end)]
|
||||
}
|
||||
|
||||
/// Slice of the source text spanning from `start` until the end
|
||||
fn str_from_to_end(&self, start: BytePos) -> &str {
|
||||
&self.src[self.src_index(start)..]
|
||||
}
|
||||
|
||||
fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
|
||||
match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
|
||||
Err(RawStrError::InvalidStarter { bad_char }) => {
|
||||
|
|
|
|||
|
|
@ -337,10 +337,11 @@ pub(super) fn check_for_substitution<'a>(
|
|||
pos: BytePos,
|
||||
ch: char,
|
||||
err: &mut Diagnostic,
|
||||
count: usize,
|
||||
) -> Option<token::TokenKind> {
|
||||
let &(_u_char, u_name, ascii_char) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?;
|
||||
|
||||
let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8()));
|
||||
let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count));
|
||||
|
||||
let Some((_ascii_char, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) else {
|
||||
let msg = format!("substitution character not found for '{}'", ch);
|
||||
|
|
@ -369,7 +370,12 @@ pub(super) fn check_for_substitution<'a>(
|
|||
"Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
|
||||
ch, u_name, ascii_char, ascii_name
|
||||
);
|
||||
err.span_suggestion(span, &msg, ascii_char, Applicability::MaybeIncorrect);
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&msg,
|
||||
ascii_char.to_string().repeat(count),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
token.clone()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr {
|
|||
pub(super) enum LhsExpr {
|
||||
NotYetParsed,
|
||||
AttributesParsed(AttrWrapper),
|
||||
AlreadyParsed(P<Expr>, bool), // (expr, starts_statement)
|
||||
AlreadyParsed { expr: P<Expr>, starts_statement: bool },
|
||||
}
|
||||
|
||||
impl From<Option<AttrWrapper>> for LhsExpr {
|
||||
|
|
@ -97,11 +97,11 @@ impl From<Option<AttrWrapper>> for LhsExpr {
|
|||
}
|
||||
|
||||
impl From<P<Expr>> for LhsExpr {
|
||||
/// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed(expr)`.
|
||||
/// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed { expr, starts_statement: false }`.
|
||||
///
|
||||
/// This conversion does not allocate.
|
||||
fn from(expr: P<Expr>) -> Self {
|
||||
LhsExpr::AlreadyParsed(expr, false)
|
||||
LhsExpr::AlreadyParsed { expr, starts_statement: false }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ impl<'a> Parser<'a> {
|
|||
lhs: LhsExpr,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let mut starts_stmt = false;
|
||||
let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs {
|
||||
let mut lhs = if let LhsExpr::AlreadyParsed { expr, starts_statement } = lhs {
|
||||
starts_stmt = starts_statement;
|
||||
expr
|
||||
} else {
|
||||
|
|
@ -562,17 +562,23 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
|
||||
match this.token.uninterpolate().kind {
|
||||
token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), // `!expr`
|
||||
token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `~expr`
|
||||
// `!expr`
|
||||
token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)),
|
||||
// `~expr`
|
||||
token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
|
||||
// `-expr`
|
||||
token::BinOp(token::Minus) => {
|
||||
make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg))
|
||||
} // `-expr`
|
||||
}
|
||||
// `*expr`
|
||||
token::BinOp(token::Star) => {
|
||||
make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref))
|
||||
} // `*expr`
|
||||
}
|
||||
// `&expr` and `&&expr`
|
||||
token::BinOp(token::And) | token::AndAnd => {
|
||||
make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
|
||||
}
|
||||
// `+lit`
|
||||
token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
|
||||
let mut err =
|
||||
LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None };
|
||||
|
|
@ -587,7 +593,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
this.bump();
|
||||
this.parse_prefix_expr(None)
|
||||
} // `+expr`
|
||||
}
|
||||
// Recover from `++x`:
|
||||
token::BinOp(token::Plus)
|
||||
if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) =>
|
||||
|
|
@ -624,7 +630,7 @@ impl<'a> Parser<'a> {
|
|||
Ok((span, self.mk_unary(op, expr)))
|
||||
}
|
||||
|
||||
// Recover on `!` suggesting for bitwise negation instead.
|
||||
/// Recover on `~expr` in favor of `!expr`.
|
||||
fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
self.sess.emit_err(TildeAsUnaryOperator(lo));
|
||||
|
||||
|
|
@ -651,7 +657,6 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Recover on `not expr` in favor of `!expr`.
|
||||
fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
// Emit the error...
|
||||
let negated_token = self.look_ahead(1, |t| t.clone());
|
||||
|
||||
let sub_diag = if negated_token.is_numeric_lit() {
|
||||
|
|
@ -672,7 +677,6 @@ impl<'a> Parser<'a> {
|
|||
),
|
||||
});
|
||||
|
||||
// ...and recover!
|
||||
self.parse_unary_expr(lo, UnOp::Not)
|
||||
}
|
||||
|
||||
|
|
@ -1471,9 +1475,8 @@ impl<'a> Parser<'a> {
|
|||
} else if self.eat(&token::Comma) {
|
||||
// Vector with two or more elements.
|
||||
let sep = SeqSep::trailing_allowed(token::Comma);
|
||||
let (remaining_exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
|
||||
let mut exprs = vec![first_expr];
|
||||
exprs.extend(remaining_exprs);
|
||||
let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
|
||||
exprs.insert(0, first_expr);
|
||||
ExprKind::Array(exprs)
|
||||
} else {
|
||||
// Vector with one element
|
||||
|
|
@ -1593,7 +1596,7 @@ impl<'a> Parser<'a> {
|
|||
vis.0
|
||||
};
|
||||
|
||||
// Suggestion involves adding a (as of time of writing this, unstable) labeled block.
|
||||
// Suggestion involves adding a labeled block.
|
||||
//
|
||||
// If there are no breaks that may use this label, suggest removing the label and
|
||||
// recover to the unmodified expression.
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ impl<'a> Parser<'a> {
|
|||
/// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
|
||||
///
|
||||
/// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs`
|
||||
/// should already have been parsed by now at this point,
|
||||
/// should already have been parsed by now at this point,
|
||||
/// if the next token is `@` then we can try to parse the more general form.
|
||||
///
|
||||
/// Consult `parse_pat_ident` for the `binding` grammar.
|
||||
|
|
|
|||
|
|
@ -164,7 +164,10 @@ impl<'a> Parser<'a> {
|
|||
// Perform this outside of the `collect_tokens_trailing_token` closure,
|
||||
// since our outer attributes do not apply to this part of the expression
|
||||
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
|
||||
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true))
|
||||
this.parse_assoc_expr_with(
|
||||
0,
|
||||
LhsExpr::AlreadyParsed { expr, starts_statement: true },
|
||||
)
|
||||
})?;
|
||||
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
|
||||
} else {
|
||||
|
|
@ -198,7 +201,10 @@ impl<'a> Parser<'a> {
|
|||
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
|
||||
let e = self.maybe_recover_from_bad_qpath(e)?;
|
||||
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
|
||||
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?;
|
||||
let e = self.parse_assoc_expr_with(
|
||||
0,
|
||||
LhsExpr::AlreadyParsed { expr: e, starts_statement: false },
|
||||
)?;
|
||||
StmtKind::Expr(e)
|
||||
};
|
||||
Ok(self.mk_stmt(lo.to(hi), kind))
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ impl CheckAttrVisitor<'_> {
|
|||
let attrs = self.tcx.hir().attrs(hir_id);
|
||||
for attr in attrs {
|
||||
let attr_is_valid = match attr.name_or_empty() {
|
||||
sym::do_not_recommend => self.check_do_not_recommend(attr.span, target),
|
||||
sym::inline => self.check_inline(hir_id, attr, span, target),
|
||||
sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
|
||||
sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
|
||||
|
|
@ -241,6 +242,16 @@ impl CheckAttrVisitor<'_> {
|
|||
);
|
||||
}
|
||||
|
||||
/// Checks if `#[do_not_recommend]` is applied on a trait impl.
|
||||
fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool {
|
||||
if let Target::Impl = target {
|
||||
true
|
||||
} else {
|
||||
self.tcx.sess.emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span });
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
|
||||
fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
|
||||
match target {
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
|
||||
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
|
||||
{
|
||||
let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
|
||||
let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().subst_identity();
|
||||
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
|
||||
&& let Some(adt_def_id) = adt_def.did().as_local()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@ use rustc_span::{Span, Symbol, DUMMY_SP};
|
|||
|
||||
use crate::lang_items::Duplicate;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_incorrect_do_not_recommend_location)]
|
||||
pub struct IncorrectDoNotRecommendLocation {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_outer_crate_level_attr)]
|
||||
pub struct OuterCrateLevelAttr;
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ trait VisibilityLike: Sized {
|
|||
let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX };
|
||||
find.visit(tcx.type_of(def_id));
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
|
||||
find.visit_trait(trait_ref);
|
||||
find.visit_trait(trait_ref.subst_identity());
|
||||
}
|
||||
find.min
|
||||
}
|
||||
|
|
@ -838,7 +838,7 @@ impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
|
|||
GenericParamDefKind::Const { has_default } => {
|
||||
self.visit(self.ev.tcx.type_of(param.def_id));
|
||||
if has_default {
|
||||
self.visit(self.ev.tcx.const_param_default(param.def_id));
|
||||
self.visit(self.ev.tcx.const_param_default(param.def_id).subst_identity());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -858,7 +858,7 @@ impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
|
|||
|
||||
fn trait_ref(&mut self) -> &mut Self {
|
||||
if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
|
||||
self.visit_trait(trait_ref);
|
||||
self.visit_trait(trait_ref.subst_identity());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ impl<'a> Resolver<'a> {
|
|||
);
|
||||
err.emit();
|
||||
} else if let Some((span, msg, sugg, appl)) = suggestion {
|
||||
err.span_suggestion(span, msg, sugg, appl);
|
||||
err.span_suggestion_verbose(span, msg, sugg, appl);
|
||||
err.emit();
|
||||
} else if let [segment] = path.as_slice() && is_call {
|
||||
err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
|
||||
|
|
|
|||
|
|
@ -2065,7 +2065,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
path: &[Segment],
|
||||
) -> Option<(Span, &'static str, String, Applicability)> {
|
||||
let (ident, span) = match path {
|
||||
[segment] if !segment.has_generic_args && segment.ident.name != kw::SelfUpper => {
|
||||
[segment]
|
||||
if !segment.has_generic_args
|
||||
&& segment.ident.name != kw::SelfUpper
|
||||
&& segment.ident.name != kw::Dyn =>
|
||||
{
|
||||
(segment.ident.to_string(), segment.ident.span)
|
||||
}
|
||||
_ => return None,
|
||||
|
|
|
|||
|
|
@ -1137,7 +1137,7 @@ impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Resolver<'_> {
|
||||
impl<'a> Resolver<'a> {
|
||||
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
|
||||
self.node_id_to_def_id.get(&node).copied()
|
||||
}
|
||||
|
|
@ -1194,6 +1194,10 @@ impl Resolver<'_> {
|
|||
self.cstore().item_generics_num_lifetimes(def_id, self.session)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sess(&self) -> &'a Session {
|
||||
self.session
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
|
|
|
|||
|
|
@ -2091,7 +2091,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
|
|||
.map(|s| {
|
||||
// Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
|
||||
// where KIND is one of "dylib", "framework", "static", "link-arg" and
|
||||
// where MODIFIERS are a comma separated list of supported modifiers
|
||||
// where MODIFIERS are a comma separated list of supported modifiers
|
||||
// (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
|
||||
// with either + or - to indicate whether it is enabled or disabled.
|
||||
// The last value specified for a given modifier wins.
|
||||
|
|
|
|||
|
|
@ -1411,6 +1411,8 @@ options! {
|
|||
"what location details should be tracked when using caller_location, either \
|
||||
`none`, or a comma separated list of location details, for which \
|
||||
valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
|
||||
log_backtrace: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||
"add a backtrace along with logging"),
|
||||
ls: bool = (false, parse_bool, [UNTRACKED],
|
||||
"list the symbols defined by a library crate (default: no)"),
|
||||
macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ scoped-tls = "1.0"
|
|||
unicode-width = "0.1.4"
|
||||
cfg-if = "1.0"
|
||||
tracing = "0.1"
|
||||
sha1 = { package = "sha-1", version = "0.10.0" }
|
||||
sha1 = "0.10.0"
|
||||
sha2 = "0.10.1"
|
||||
md5 = { package = "md-5", version = "0.10.0" }
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@ impl InlineAsmRegClass {
|
|||
}
|
||||
|
||||
/// Returns a suggested template modifier to use for this type and an
|
||||
/// example of a register named formatted with it.
|
||||
/// example of a register named formatted with it.
|
||||
///
|
||||
/// Such suggestions are useful if a type smaller than the full register
|
||||
/// size is used and a modifier can be used to point to the subregister of
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use super::infcx_ext::InferCtxtExt;
|
||||
use super::{
|
||||
fixme_instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty,
|
||||
EvalCtxt, Goal,
|
||||
instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty, EvalCtxt,
|
||||
Goal,
|
||||
};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
|
|
@ -121,11 +121,8 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
|
|||
// canonical wrt the caller.
|
||||
for Candidate { source, result } in normalized_candidates {
|
||||
self.infcx.probe(|_| {
|
||||
let candidate_certainty = fixme_instantiate_canonical_query_response(
|
||||
&self.infcx,
|
||||
&orig_values,
|
||||
result,
|
||||
);
|
||||
let candidate_certainty =
|
||||
instantiate_canonical_query_response(&self.infcx, &orig_values, result);
|
||||
|
||||
// FIXME: This is a bit scary if the `normalizes_to_goal` overflows.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@
|
|||
//! FIXME(@lcnr): Write that section, feel free to ping me if you need help here
|
||||
//! before then or if I still haven't done that before January 2023.
|
||||
use super::overflow::OverflowData;
|
||||
use super::CanonicalGoal;
|
||||
use super::{CanonicalGoal, Certainty, MaybeCause, Response};
|
||||
use super::{EvalCtxt, QueryResult};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use std::{cmp::Ordering, collections::hash_map::Entry};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -111,11 +112,11 @@ impl<'tcx> EvalCtxt<'tcx> {
|
|||
// No entry, simply push this goal on the stack after dealing with overflow.
|
||||
Entry::Vacant(v) => {
|
||||
if self.overflow_data.has_overflow(cache.stack.len()) {
|
||||
return Err(self.deal_with_overflow());
|
||||
return Err(self.deal_with_overflow(goal));
|
||||
}
|
||||
|
||||
v.insert(ProvisionalEntry {
|
||||
response: fixme_response_yes_no_constraints(),
|
||||
response: response_no_constraints(self.tcx, goal, Certainty::Yes),
|
||||
depth: cache.stack.len(),
|
||||
});
|
||||
cache.stack.push(StackElem { goal, has_been_used: false });
|
||||
|
|
@ -150,7 +151,11 @@ impl<'tcx> EvalCtxt<'tcx> {
|
|||
{
|
||||
Err(entry.response)
|
||||
} else {
|
||||
Err(fixme_response_maybe_no_constraints())
|
||||
Err(response_no_constraints(
|
||||
self.tcx,
|
||||
goal,
|
||||
Certainty::Maybe(MaybeCause::Ambiguity),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -248,10 +253,39 @@ impl<'tcx> EvalCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fixme_response_yes_no_constraints<'tcx>() -> QueryResult<'tcx> {
|
||||
unimplemented!()
|
||||
}
|
||||
pub(super) fn response_no_constraints<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: Canonical<'tcx, impl Sized>,
|
||||
certainty: Certainty,
|
||||
) -> QueryResult<'tcx> {
|
||||
let var_values = goal
|
||||
.variables
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, info)| match info.kind {
|
||||
CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
|
||||
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into()
|
||||
}
|
||||
CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
|
||||
let br = ty::BoundRegion {
|
||||
var: ty::BoundVar::from_usize(i),
|
||||
kind: ty::BrAnon(i as u32, None),
|
||||
};
|
||||
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
|
||||
}
|
||||
CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
|
||||
.mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty)
|
||||
.into(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
fn fixme_response_maybe_no_constraints<'tcx>() -> QueryResult<'tcx> {
|
||||
unimplemented!()
|
||||
Ok(Canonical {
|
||||
max_universe: goal.max_universe,
|
||||
variables: goal.variables,
|
||||
value: Response {
|
||||
var_values: CanonicalVarValues { var_values },
|
||||
external_constraints: Default::default(),
|
||||
certainty,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
|||
let mut errors = Vec::new();
|
||||
for i in 0.. {
|
||||
if !infcx.tcx.recursion_limit().value_within_limit(i) {
|
||||
unimplemented!("overflow")
|
||||
unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
|
||||
}
|
||||
|
||||
let mut has_changed = false;
|
||||
|
|
|
|||
|
|
@ -19,15 +19,19 @@
|
|||
|
||||
use std::mem;
|
||||
|
||||
use rustc_infer::infer::canonical::OriginalQueryValues;
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
|
||||
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::infer::canonical::Certainty as OldCertainty;
|
||||
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use crate::traits::ObligationCause;
|
||||
|
||||
use self::cache::response_no_constraints;
|
||||
use self::infcx_ext::InferCtxtExt;
|
||||
|
||||
mod assembly;
|
||||
|
|
@ -119,7 +123,7 @@ pub enum MaybeCause {
|
|||
}
|
||||
|
||||
/// Additional constraints returned on success.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable, Default)]
|
||||
pub struct ExternalConstraints<'tcx> {
|
||||
// FIXME: implement this.
|
||||
regions: (),
|
||||
|
|
@ -175,7 +179,7 @@ impl<'tcx> EvalCtxt<'tcx> {
|
|||
let canonical_response = self.evaluate_canonical_goal(canonical_goal)?;
|
||||
Ok((
|
||||
true, // FIXME: check whether `var_values` are an identity substitution.
|
||||
fixme_instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
|
||||
instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +212,8 @@ impl<'tcx> EvalCtxt<'tcx> {
|
|||
// of `PredicateKind` this is the case and it is and faster than instantiating and
|
||||
// recanonicalizing.
|
||||
let Goal { param_env, predicate } = canonical_goal.value;
|
||||
if let Some(kind) = predicate.kind().no_bound_vars() {
|
||||
|
||||
if let Some(kind) = predicate.kind().no_bound_vars_ignoring_escaping(self.tcx) {
|
||||
match kind {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => self.compute_trait_goal(
|
||||
canonical_goal.unchecked_rebind(Goal { param_env, predicate }),
|
||||
|
|
@ -234,7 +239,10 @@ impl<'tcx> EvalCtxt<'tcx> {
|
|||
| ty::PredicateKind::ConstEvaluatable(_)
|
||||
| ty::PredicateKind::ConstEquate(_, _)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(_)
|
||||
| ty::PredicateKind::Ambiguous => unimplemented!(),
|
||||
| ty::PredicateKind::Ambiguous => {
|
||||
// FIXME
|
||||
response_no_constraints(self.tcx, canonical_goal, Certainty::Yes)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let (infcx, goal, var_values) =
|
||||
|
|
@ -248,16 +256,18 @@ impl<'tcx> EvalCtxt<'tcx> {
|
|||
|
||||
fn compute_type_outlives_goal(
|
||||
&mut self,
|
||||
_goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
|
||||
goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
todo!()
|
||||
// FIXME
|
||||
response_no_constraints(self.tcx, goal, Certainty::Yes)
|
||||
}
|
||||
|
||||
fn compute_region_outlives_goal(
|
||||
&mut self,
|
||||
_goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
|
||||
goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
todo!()
|
||||
// FIXME
|
||||
response_no_constraints(self.tcx, goal, Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -300,10 +310,27 @@ impl<'tcx> EvalCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fixme_instantiate_canonical_query_response<'tcx>(
|
||||
_: &InferCtxt<'tcx>,
|
||||
_: &OriginalQueryValues<'tcx>,
|
||||
_: CanonicalResponse<'tcx>,
|
||||
fn instantiate_canonical_query_response<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
original_values: &OriginalQueryValues<'tcx>,
|
||||
response: CanonicalResponse<'tcx>,
|
||||
) -> Certainty {
|
||||
unimplemented!()
|
||||
let Ok(InferOk { value, obligations }) = infcx
|
||||
.instantiate_query_response_and_region_obligations(
|
||||
&ObligationCause::dummy(),
|
||||
ty::ParamEnv::empty(),
|
||||
original_values,
|
||||
&response.unchecked_map(|resp| QueryResponse {
|
||||
var_values: resp.var_values,
|
||||
region_constraints: QueryRegionConstraints::default(),
|
||||
certainty: match resp.certainty {
|
||||
Certainty::Yes => OldCertainty::Proven,
|
||||
Certainty::Maybe(_) => OldCertainty::Ambiguous,
|
||||
},
|
||||
opaque_types: resp.external_constraints.opaque_types,
|
||||
value: resp.certainty,
|
||||
}),
|
||||
) else { bug!(); };
|
||||
assert!(obligations.is_empty());
|
||||
value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Limit;
|
||||
|
||||
use super::cache::response_no_constraints;
|
||||
use super::{Certainty, EvalCtxt, MaybeCause, QueryResult};
|
||||
|
||||
/// When detecting a solver overflow, we return ambiguity. Overflow can be
|
||||
|
|
@ -49,9 +51,12 @@ impl OverflowData {
|
|||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'tcx> {
|
||||
pub(super) fn deal_with_overflow(&mut self) -> QueryResult<'tcx> {
|
||||
pub(super) fn deal_with_overflow(
|
||||
&mut self,
|
||||
goal: Canonical<'tcx, impl Sized>,
|
||||
) -> QueryResult<'tcx> {
|
||||
self.overflow_data.deal_with_overflow();
|
||||
fixme_response_overflow_no_constraints()
|
||||
response_no_constraints(self.tcx, goal, Certainty::Maybe(MaybeCause::Overflow))
|
||||
}
|
||||
|
||||
/// A `while`-loop which tracks overflow.
|
||||
|
|
@ -74,7 +79,3 @@ impl<'tcx> EvalCtxt<'tcx> {
|
|||
Ok(Certainty::Maybe(MaybeCause::Overflow))
|
||||
}
|
||||
}
|
||||
|
||||
fn fixme_response_overflow_no_constraints<'tcx>() -> QueryResult<'tcx> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
) {
|
||||
let tcx = acx.cx.tcx;
|
||||
let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
|
||||
let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
|
||||
if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs)
|
||||
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
) {
|
||||
let tcx = acx.cx.tcx;
|
||||
|
||||
let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
|
||||
if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
|
||||
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ pub fn overlapping_impls(
|
|||
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
|
||||
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
|
||||
let may_overlap = match (impl1_ref, impl2_ref) {
|
||||
(Some(a), Some(b)) => iter::zip(a.substs, b.substs)
|
||||
(Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs)
|
||||
.all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
|
||||
(None, None) => {
|
||||
let self_ty1 = tcx.type_of(impl1_def_id);
|
||||
|
|
@ -126,7 +126,7 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
|
|||
let header = ty::ImplHeader {
|
||||
impl_def_id,
|
||||
self_ty: tcx.bound_type_of(impl_def_id).subst(tcx, impl_substs),
|
||||
trait_ref: tcx.bound_impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
|
||||
trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
|
||||
predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
|
||||
};
|
||||
|
||||
|
|
@ -461,7 +461,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
|
|||
|
||||
// We only except this routine to be invoked on implementations
|
||||
// of a trait, not inherent implementations.
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
|
||||
debug!("orphan_check: trait_ref={:?}", trait_ref);
|
||||
|
||||
// If the *trait* is local to the crate, ok.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue