do not allow inference in `predicate_must_hold` (alternative approach)
See the FCP description for more info, but tl;dr is that we should not return `EvaluatedToOkModuloRegions` if an obligation may hold only with some choice of inference vars being constrained.
Attempts to solve this in the approach laid out by lcnr here: https://github.com/rust-lang/rust/pull/109558#discussion_r1147318134, rather than by eagerly replacing infer vars with placeholders which is a bit too restrictive.
r? `@ghost`
Note user-facing types of coercion failure
When coercing, for example, `Box<A>` into `Box<dyn B>`, make sure that any failure notes mention *those* specific types, rather than mentioning inner types, like "the cast from `A` to `dyn B`".
I expect end-users are often confused when we skip layers of types and only mention the "innermost" part of a coercion, especially when other notes point at HIR, e.g. #111406.
Uplift `clippy::{drop,forget}_{ref,copy}` lints
This PR aims at uplifting the `clippy::drop_ref`, `clippy::drop_copy`, `clippy::forget_ref` and `clippy::forget_copy` lints.
Those lints are/were declared in the correctness category of clippy because they lint on useless and most probably is not what the developer wanted.
## `drop_ref` and `forget_ref`
The `drop_ref` and `forget_ref` lint checks for calls to `std::mem::drop` or `std::mem::forget` with a reference instead of an owned value.
### Example
```rust
let mut lock_guard = mutex.lock();
std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex
// still locked
operation_that_requires_mutex_to_be_unlocked();
```
### Explanation
Calling `drop` or `forget` on a reference will only drop the reference itself, which is a no-op. It will not call the `drop` or `forget` method on the underlying referenced value, which is likely what was intended.
## `drop_copy` and `forget_copy`
The `drop_copy` and `forget_copy` lint checks for calls to `std::mem::forget` or `std::mem::drop` with a value that derives the Copy trait.
### Example
```rust
let x: i32 = 42; // i32 implements Copy
std::mem::forget(x) // A copy of x is passed to the function, leaving the
// original unaffected
```
### Explanation
Calling `std::mem::forget` [does nothing for types that implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the value will be copied and moved into the function on invocation.
-----
Followed the instructions for uplift a clippy describe here: https://github.com/rust-lang/rust/pull/99696#pullrequestreview-1134072751
cc `@m-ou-se` (as T-libs-api leader because the uplifting was discussed in a recent meeting)
Don't compute trait super bounds unless they're positive
Fixes#111207
The comment is modified to explain the rationale for why we even have this recursive call to supertraits in the first place, which doesn't apply to negative bounds since they don't elaborate at all.
Tweak await span to not contain dot
Fixes a discrepancy between method calls and await expressions where the latter are desugared to have a span that *contains* the dot (i.e. `.await`) but method call identifiers don't contain the dot. This leads to weird suggestions suggestions in borrowck -- see linked issue.
Fixes#110761
This mostly touches a bunch of tests to tighten their `await` span.
Use `?0` notation for ty/ct/int/float/region vars
Aligns the notation for infer vars that T-types and friends most often uses for inference variables with the notation in the compiler (which is kinda a sigil nightmare IMO: `_#`) by adopting `?0` style infer vars.
This mostly affects debug output since verbose infer vars shouldn't show up in user-facing places.
Does this need an MCP? It's debug output, so I'm thinking no, but happy to open one. 🤔
r? types
Clone region var origins instead of taking them in borrowck
Fixes an issue with the new solver where reporting a borrow-checker error ICEs because it calls `InferCtxt::evaluate_obligation`.
This also removes a handful of unnecessary `tcx.infer_ctxt().build()` calls that are only there to mitigate this same exact issue, but with the old solver.
Fixescompiler-errors/next-solver-hir-issues#12.
----
This implements `@aliemjay's` solution where we just don't *take* the region constraints, but clone them. This potentially makes it easier to write a bug about taking region constraints twice or never at all, but again, not many folks are touching this code.
don't uniquify regions when canonicalizing
uniquifying causes a bunch of issues, most notably it causes `AliasEq(<?x as Trait<'a>>::Assoc, <?x as Trait<'a>>::Assoc)` to result in ambiguity because both `normalizes-to` paths result in ambiguity and substs equate should trivially succeed but doesn't because we uniquified `'a` to two different regions.
I originally added uniquification to make it easier to deal with requirement 6 from the dev-guide: https://rustc-dev-guide.rust-lang.org/solve/trait-solving.html#requirements
> ### 6. Trait solving must be (free) lifetime agnostic
>
> Trait solving during codegen should have the same result as during typeck. As we erase
> all free regions during codegen we must not rely on them during typeck. A noteworthy example
> is special behavior for `'static`.
cc https://github.com/rust-lang/rustc-dev-guide/pull/1671
Relying on regions being identical may cause ICE during MIR typeck, but even without this PR we can end up relying on that as type inference vars can resolve to types which contain an identical region. Let's land this and deal with any ICE that crop up as we go. Will look at this issue again before stabilization.
r? ```@compiler-errors```
Erase lifetimes above `ty::INNERMOST` when probing ambiguous types
Turns out that `TyCtxt::replace_escaping_bound_vars_uncached` only erases bound vars exactly at `ty::INNERMOST`, and not everything above. This regresses the suggestions for non-lifetime binders, but oh well, I don't really care about those.
Fixes#110052
Instantiate instead of erasing binder when probing param methods
Fixes#108836
There is a really old comment saying that a `WhereClauseCandidate` probe candidate "should not contain any inference variables", but I'm not really confident that that comment applies anymore. In contrast, other candidates that we assemble during method probe contain inference variables in their substitutions (e.g. `InherentImplCandidate`)...
Since this change is made only to support a nightly feature, I'm happy to gate the new behavior behind this feature flag or discuss it further.
r? types
Implement support for `GeneratorWitnessMIR` in new solver
r? ```@cjgillot```
I mostly want this to cut down the number of failing UI tests when running the UI test suite with `--compare-mode=next-solver`, but there doesn't seem like much reason to block implementing this since it adds minimal complexity to the existing structural traits impl in the new solver.
If others are against adding this for some reason, then maybe we should just make `GeneratorWitnessMIR` return `NoSolution` for these traits. Anything but an ICE please 😸🧊
Validate `ignore` and `only` compiletest directive, and add human-readable ignore reasons
This PR adds strict validation for the `ignore` and `only` compiletest directives, failing if an unknown value is provided to them. Doing so uncovered 79 tests in `tests/ui` that had invalid directives, so this PR also fixes them.
Finally, this PR adds human-readable ignore reasons when tests are ignored due to `ignore` or `only` directives, like *"only executed when the architecture is aarch64"* or *"ignored when the operative system is windows"*. This was the original reason why I started working on this PR and #108659, as we need both of them for Ferrocene.
The PR is a draft because the code is extremely inefficient: it calls `rustc --print=cfg --target $target` for every rustc target (to gather the list of allowed ignore values), which on my system takes between 4s and 5s, and performs a lot of allocations of constant values. I'll fix both of them in the coming days.
r? `@ehuss`
Closures always implement `FnOnce` in new solver
We should process `[closure]: FnOnce(Tys...) -> Ty` obligations *before* fallback and closure analysis. We can do this by taking advantage of the fact that `FnOnce` is always implemented by closures, even before we definitely know the closure kind.
Fixescompiler-errors/next-solver-hir-issues#15
r? ``@oli-obk`` (trying to spread the reviewer load for new trait solver prs, and this one is pretty self-contained, though feel free to reassign 😸)
Don't ICE on placeholder consts in deep reject
Since we canonicalize const params into placeholder consts, we need to be able to handle them during deep reject.
r? `@lcnr` (though maybe `@oli-obk` can look at this one too, if he wants 😸)
Fixescompiler-errors/next-solver-hir-issues#10
Canonicalize float var as float in new solver
Typo in new canonicalizer -- we should be canonicalizing float vars as `CanonicalTyVarKind::Float`, not `CanonicalTyVarKind::Int`.
Fixescompiler-errors/next-solver-hir-issues#9
Don't ICE on `DiscriminantKind` projection in new solver
As title says, since we now actually call `Ty::discriminant_kind` on placeholder types 😃
Also drive-by simplify `Pointee::Metadata` projection logic, and fix the UI test because the `<T as Pointee>::Metadata` tests weren't actually exercising the new projection logic, since we still eagerly normalize (which hits `project.rs` in the old solver) in HIR typeck.
r? `@lcnr` tho feel free to re-roll, this pr is very low-priority and not super specific to the new trait solver.
Fixescompiler-errors/next-solver-hir-issues#14
Implement non-const `Destruct` trait in new solver
Makes it so that we can call stdlib methods like `Option::map` in **non-const** environments, since *many* stdlib methods have `Destruct` bounds 😅
This doesn't bother to implement `const Destruct` yet, but it shouldn't be too hard to do so. Just didn't bother since we already don't have much support for const traits in the new solver anyways. I'd be happy to add skeleton support for `const Destruct`, though, if the reviewer desires.
Rollup of 7 pull requests
Successful merges:
- #108541 (Suppress `opaque_hidden_inferred_bound` for nested RPITs)
- #109137 (resolve: Querify most cstore access methods (subset 2))
- #109380 (add `known-bug` test for unsoundness issue)
- #109462 (Make alias-eq have a relation direction (and rename it to alias-relate))
- #109475 (Simpler checked shifts in MIR building)
- #109504 (Stabilize `arc_into_inner` and `rc_into_inner`.)
- #109506 (make param bound vars visibly bound vars with -Zverbose)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
new solver cleanup + implement coherence
the cleanup:
- change `Certainty::unify_and` to consider ambig + overflow to be ambig
- rename `trait_candidate_should_be_dropped_in_favor_of` to `candidate_should_be_dropped_in_favor_of`
- remove outdated fixme
For coherence I mostly just add an ambiguous candidate if the current trait ref is unknowable. I am doing the same for reservation impl where I also just add an ambiguous candidate.
a general type system cleanup
removes the helper functions `traits::fully_solve_X` as they add more complexity then they are worth. It's confusing which of these helpers should be used in which context.
changes the way we deal with overflow to always add depth in `evaluate_predicates_recursively`. It may make sense to actually fully transition to not have `recursion_depth` on obligations but that's probably a bit too much for this PR.
also removes some other small - and imo unnecessary - helpers.
r? types
Only implement Fn* traits for extern "Rust" safe function pointers and items
Since calling the function via an `Fn` trait will assume `extern "Rust"` ABI and not do any safety checks, only safe `extern "Rust"` function can implement the `Fn` traits. This syncs the logic between the old solver and the new solver.
r? `@compiler-errors`
feat: implement better error for manual impl of `Fn*` traits
Fixes#39259
cc `@estebank` (you gave me some advice in the linked issue, would you like to review?)
Rollup of 8 pull requests
Successful merges:
- #108754 (Retry `pred_known_to_hold_modulo_regions` with fulfillment if ambiguous)
- #108759 (1.41.1 supported 32-bit Apple targets)
- #108839 (Canonicalize root var when making response from new solver)
- #108856 (Remove DropAndReplace terminator)
- #108882 (Tweak E0740)
- #108898 (Set `LIBC_CHECK_CFG=1` when building Rust code in bootstrap)
- #108911 (Improve rustdoc-gui/tester.js code a bit)
- #108916 (Remove an unused return value in `rustc_hir_typeck`)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Canonicalize root var when making response from new solver
During trait solving, if we equate two inference variables `?0` and `?1` but don't equate them with any rigid types, then `InferCtxt::probe_ty_var` will return `Err` for both of these. The canonicalizer code will then canonicalize the variables independently(!), and the response will not reflect the fact that these two variables have been made equal.
This hinders inference and I also don't think it's sound? I haven't thought too much about it past that, so let's talk about it.
r? ``@lcnr``
always resolve to universal regions if possible
`RegionConstraintCollector::opportunistic_resolve_var`, which is used in canonicalization and projection logic, doesn't resolve the region var to an equal universal region. So if we have equated `'static == '1 == '2`, it doesn't resolve `'1` or `'2` to `'static`. Now it does!
Addresses review comment https://github.com/rust-lang/rust/pull/107376#discussion_r1093233687.
r? `@lcnr`
Bless tests and show an introduced unsoundness related to
exits<'a> { forall<'b> { 'a == 'b } }.
We now resolve the var ?a in U0 to the placeholder !b in U1.
Deny capturing late-bound non-lifetime param in anon const
Introduce a new AnonConstBoundary so we can detect when we capture a late-bound non-lifetime param with `non_lifetime_binders` enabled.
In the future, we could technically do something like introduce an early-bound parameter on the anon const, and stick the late-bound param in its substs (kinda like how we turn late-bound lifetimes in opaques into early-bound ones). But for now, just deny it so we don't ICE.
Fixes#108191
Commit some new solver tests
Lazy norm is hard.
`<?0 as Trait>::Assoc = ?0` ... probably should emit an alias-eq goal, but currently we don't do that. Right now it fails with a cyclical ty error.
Also committed a check-pass test that broken when I attempted to fix this (unsuccessfully).
r? types
Rollup of 8 pull requests
Successful merges:
- #107062 (Do some cleanup of doc/index.md)
- #107890 (Lint against `Iterator::map` receiving a callable that returns `()`)
- #108431 (Add regression test for #107918)
- #108432 (test: drop unused deps)
- #108436 (make "proc macro panicked" translatable)
- #108444 (docs/test: add UI test and docs for `E0476`)
- #108449 (Do not lint ineffective unstable trait impl for unresolved trait)
- #108456 (Complete migrating `ast_passes` to derive diagnostics)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Consider `tests/ui/const-generics/generic_const_exprs/issue-102768.stderr`,
the error message where it gives additional notes about where the associated
type is defined, and how the dead code lint doesn't have an article,
like in `tests/ui/lint/dead-code/issue-85255.stderr`. They don't have
articles, so it seems unnecessary to have one here.
Use DefKind to give more item kind information during BindingObligation note
The current label says "required by a bound in this". When I see that label, my immediate impression is "this... **what**?". It feels like it was cut short.
Alternative to this would be saying "in this item", but adding the item kind is strictly more informational and adds very little overhead to the existing error presentation.
Fix some more `non_lifetime_binders` stuff with higher-ranked trait bounds
1. When assembling candidates for `for<T> T: Sized`, we can't ICE because the self-type is a bound type.
2. Fix an issue where, when canonicalizing in non-universe preserving mode, we don't actually set the universe for placeholders to the root even though we do the same for region vars.
3. Make `Placeholder("T")` format like `T` in error messages.
Fixes#108180Fixes#108182
r? types
Do not ICE on unmet trait alias impl bounds
Fixes#108132
I've also added some documentation to the `impl_def_id` field of `DerivedObligationCause` to try and minimise the risk of such errors in future.
r? `@compiler-errors`
Implement partial support for non-lifetime binders
This implements support for non-lifetime binders. It's pretty useless currently, but I wanted to put this up so the implementation can be discussed.
Specifically, this piggybacks off of the late-bound lifetime collection code in `rustc_hir_typeck::collect::lifetimes`. This seems like a necessary step given the fact we don't resolve late-bound regions until this point, and binders are sometimes merged.
Q: I'm not sure if I should go along this route, or try to modify the earlier nameres code to compute the right bound var indices for type and const binders eagerly... If so, I'll need to rename all these queries to something more appropriate (I've done this for `resolve_lifetime::Region` -> `resolve_lifetime::ResolvedArg`)
cc rust-lang/types-team#81
r? `@ghost`
Most tests involving save-analysis were removed, but I kept a few where
the `-Zsave-analysis` was an add-on to the main thing being tested,
rather than the main thing being tested.
For `x.py install`, the `rust-analysis` target has been removed.
For `x.py dist`, the `rust-analysis` target has been kept in a
degenerate form: it just produces a single file `reduced.json`
indicating that save-analysis has been removed. This is necessary for
rustup to keep working.
Closes#43606.
Rollup of 9 pull requests
Successful merges:
- #105019 (Add parentheses properly for borrowing suggestion)
- #106001 (Stop at the first `NULL` argument when iterating `argv`)
- #107098 (Suggest function call on pattern type mismatch)
- #107490 (rustdoc: remove inconsistently-present sidebar tooltips)
- #107855 (Add a couple random projection tests for new solver)
- #107857 (Add ui test for implementation on projection)
- #107878 (Clarify `new_size` for realloc means bytes)
- #107888 (revert #107074, add regression test)
- #107900 (Zero the `REPARSE_MOUNTPOINT_DATA_BUFFER` header)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Refine error spans for "The trait bound `T: Trait` is not satisfied" when passing literal structs/tuples
This PR adds a new heuristic which refines the error span reported for "`T: Trait` is not satisfied" errors, by "drilling down" into individual fields of structs/enums/tuples to point to the "problematic" value.
Here's a self-contained example of the difference in error span:
```rs
struct Burrito<Filling> {
filling: Filling,
}
impl <Filling: Delicious> Delicious for Burrito<Filling> {}
fn eat_delicious_food<Food: Delicious>(food: Food) {}
fn will_type_error() {
eat_delicious_food(Burrito { filling: Kale });
// ^~~~~~~~~~~~~~~~~~~~~~~~~ (before) The trait bound `Kale: Delicious` is not satisfied
// ^~~~ (after) The trait bound `Kale: Delicious` is not satisfied
}
```
(kale is fine, this is just a silly food-based example)
Before this PR, the error span is identified as the entire argument to the generic function `eat_delicious_food`. However, since only `Kale` is the "problematic" part, we can point at it specifically. In particular, the primary error message itself mentions the missing `Kale: Delicious` trait bound, so it's much clearer if this part is called out explicitly.
---
The _existing_ heuristic tries to label the right function argument in `point_at_arg_if_possible`. It goes something like this:
- Look at the broken base trait `Food: Delicious` and find which generics it mentions (in this case, only `Food`)
- Look at the parameter type definitions and find which of them mention `Filling` (in this case, only `food`)
- If there is exactly one relevant parameter, label the corresponding argument with the error span, instead of the entire call
This PR extends this heuristic by further refining the resulting expression span in the new `point_at_specific_expr_if_possible` function. For each `impl` in the (broken) chain, we apply the following strategy:
The strategy to determine this span involves connecting information about our generic `impl`
with information about our (struct) type and the (struct) literal expression:
- Find the `impl` (`impl <Filling: Delicious> Delicious for Burrito<Filling>`)
that links our obligation (`Kale: Delicious`) with the parent obligation (`Burrito<Kale>: Delicious`)
- Find the "original" predicate constraint in the impl (`Filling: Delicious`) which produced our obligation.
- Find all of the generics that are mentioned in the predicate (`Filling`).
- Examine the `Self` type in the `impl`, and see which of its type argument(s) mention any of those generics.
- Examing the definition for the `Self` type, and identify (for each of its variants) if there's a unique field
which uses those generic arguments.
- If there is a unique field mentioning the "blameable" arguments, use that field for the error span.
Before we do any of this logic, we recursively call `point_at_specific_expr_if_possible` on the parent
obligation. Hence we refine the `expr` "outwards-in" and bail at the first kind of expression/impl we don't recognize.
This function returns a `Result<&Expr, &Expr>` - either way, it returns the `Expr` whose span should be
reported as an error. If it is `Ok`, then it means it refined successfull. If it is `Err`, then it may be
only a partial success - but it cannot be refined even further.
---
I added a new test file which exercises this new behavior. A few existing tests were affected, since their error spans are now different. In one case, this leads to a different code suggestion for the autofix - although the new suggestion isn't _wrong_, it is different from what used to be.
This change doesn't create any new errors or remove any existing ones, it just adjusts the spans where they're presented.
---
Some considerations: right now, this check occurs in addition to some similar logic in `adjust_fulfillment_error_for_expr_obligation` function, which tidies up various kinds of error spans (not just trait-fulfillment error). It's possible that this new code would be better integrated into that function (or another one) - but I haven't looked into this yet.
Although this code only occurs when there's a type error, it's definitely not as efficient as possible. In particular, there are definitely some cases where it degrades to quadratic performance (e.g. for a trait `impl` with 100+ generic parameters or 100 levels deep nesting of generic types). I'm not sure if these are realistic enough to worry about optimizing yet.
There's also still a lot of repetition in some of the logic, where the behavior for different types (namely, `struct` vs `enum` variant) is _similar_ but not the same.
---
I think the biggest win here is better targeting for tuples; in particular, if you're using tuples + traits to express variadic-like functions, the compiler can't tell you which part of a tuple has the wrong type, since the span will cover the entire argument. This change allows the individual field in the tuple to be highlighted, as in this example:
```
// NEW
LL | want(Wrapper { value: (3, q) });
| ---- ^ the trait `T3` is not implemented for `Q`
// OLD
LL | want(Wrapper { value: (3, q) });
| ---- ^~~~~~~~~~~~~~~~~~~~~~~~~ the trait `T3` is not implemented for `Q`
```
Especially with large tuples, the existing error spans are not very effective at quickly narrowing down the source of the problem.
Modify primary span label for E0308
Looking at the reactions to https://hachyderm.io/`@ekuber/109622160673605438,` a lot of people seem to have trouble understanding the current output, where the primary span label on type errors talks about the specific types that diverged, but these can be deeply nested type parameters. Because of that we could see "expected i32, found u32" in the label while the note said "expected Vec<i32>, found Vec<u32>". This understandably confuses people. I believe that once people learn to read these errors it starts to make more sense, but this PR changes the output to be more in line with what people might expect, without sacrificing terseness.
Fix#68220.
Skip possible where_clause_object_safety lints when checking `multiple_supertrait_upcastable`
Fix#106247
To achieve this, I lifted the `WhereClauseReferencesSelf` out from `object_safety_violations` and move it into `is_object_safe` (which is changed to a new query).
cc `@dtolnay`
r? `@compiler-errors`
Implement some more new solver candidates and fix some bugs
First, fix some bugs:
1. `IndexVec::drain_enumerated(a..b)` does not give us an iterator of index keys + items enumerated from `a..b`, but from `0..(b-a)`... That caused a bug. See first commit for the fix.
2. Implement the `_: Trait` ambiguity hack. I put it in assemble, let me know if it should live elsewhere. This is important, since we otherwise consider `_: Sized` to have no solutions, and nothing passes!
3. Swap `Ambiguity` and `Unimplemented` cases for the new solver. Sorry for accidentally swapping them 😄
4. Check GATs' own predicates during projection confirmation.
Then implement a few builtin traits:
5. Implement `PointerSized`. Pretty independent.
6. Implement `Fn` family of traits for fnptr, fndef, and closures. Closures are currently broken because `FulfillCtxt::relationships` is intentionally left unimplemented. See comment in the test.
r? ```@lcnr```
Emit a hint for bad call return types due to generic arguments
When the return type of a function call depends on the type of an argument, e.g.
```
fn foo<T>(x: T) -> T {
x
}
```
and the expected type is set due to either an explicitly typed binding, or because the call to the function is in a tail position without semicolon, the current error implies that the argument in the call has the wrong type.
This new hint highlights that the expected type doesn't match the returned type, which matches the argument type, and that that's why we're flagging the argument type.
Fixes#43608.
I encountered an instance where an `FnPtr` implemented a trait, but I was passing an `FnDef`. To
the end user, there is really no way to differentiate each of them, but it is necessary to cast
to the generic function in order to compile. It is thus useful to suggest `as` in the help note,
(even if the Fn output implements the trait).
When the return type of a function call depends on the type of an
argument, e.g.
```
fn foo<T>(x: T) -> T {
x
}
```
and the expected type is set due to either an explicitly typed
binding, or because the call to the function is in a tail position
without semicolon, the current error implies that the argument in the
call has the wrong type.
This new hint highlights that the expected type doesn't match the
returned type, which matches the argument type, and that that's why
we're flagging the argument type.
Fixes#43608.
Prefer non-`[type error]` candidates during selection
Fixes#102130Fixes#106351
r? types
note: Alternatively we could filter out error where-clauses during param-env construction? But we still need to filter out impls with errors during `match_impl`, I think.