about summary refs log tree commit diff
path: root/compiler/rustc_infer/src
AgeCommit message (Collapse)AuthorLines
2024-03-01Rebase fallout from TypeRelating::binders, inline higher_ranked_subMichael Goulet-66/+51
2024-03-01Fallout from removing a_is_expectedMichael Goulet-62/+18
2024-03-01Remove a_is_expected from combine relationsMichael Goulet-127/+71
2024-03-01Get rid of some sub_exp and eq_expMichael Goulet-9/+9
2024-03-01Remove causeMichael Goulet-24/+2
2024-03-01Combine sub and eqMichael Goulet-485/+350
2024-03-01Preserve variance on error in generalizerMichael Goulet-2/+2
2024-02-29Auto merge of #118247 - spastorino:type-equality-subtyping, r=lcnrbors-6/+29
change equate for binders to not rely on subtyping *summary by `@spastorino` and `@lcnr*` ### Context The following code: ```rust type One = for<'a> fn(&'a (), &'a ()); type Two = for<'a, 'b> fn(&'a (), &'b ()); mod my_api { use std::any::Any; use std::marker::PhantomData; pub struct Foo<T: 'static> { a: &'static dyn Any, _p: PhantomData<*mut T>, // invariant, the type of the `dyn Any` } impl<T: 'static> Foo<T> { pub fn deref(&self) -> &'static T { match self.a.downcast_ref::<T>() { None => unsafe { std::hint::unreachable_unchecked() }, Some(a) => a, } } pub fn new(a: T) -> Foo<T> { Foo::<T> { a: Box::leak(Box::new(a)), _p: PhantomData, } } } } use my_api::*; fn main() { let foo = Foo::<One>::new((|_, _| ()) as One); foo.deref(); let foo: Foo<Two> = foo; foo.deref(); } ``` has UB from hitting the `unreachable_unchecked`. This happens because `TypeId::of::<One>()` is not the same as `TypeId::of::<Two>()` despite them being considered the same types by the type checker. Currently the type checker considers binders to be equal if subtyping succeeds in both directions: `for<'a> T<'a> eq for<'b> U<'b>` holds if `for<'a> exists<'b> T<'b> <: T'<a> AND for<'b> exists<'a> T<'a> <: T<'b>` holds. This results in `for<'a> fn(&'a (), &'a ())` and `for<'a, 'b> fn(&'a (), &'b ())` being equal in the type system. `TypeId` is computed by looking at the *structure* of a type. Even though these types are semantically equal, they have a different *structure* resulting in them having different `TypeId`. This can break invariants of unsafe code at runtime and is unsound when happening at compile time, e.g. when using const generics. So as seen in `main`, we can assign a value of type `Foo::<One>` to a binding of type `Foo<Two>` given those are considered the same type but then when we call `deref`, it calls `downcast_ref` that relies on `TypeId` and we would hit the `None` arm as these have different `TypeId`s. As stated in https://github.com/rust-lang/rust/issues/97156#issuecomment-1879030033, this causes the API of existing crates to be unsound. ## What should we do about this The same type resulting in different `TypeId`s is a significant footgun, breaking a very reasonable assumptions by authors of unsafe code. It will also be unsound by itself once they are usable in generic contexts with const generics. There are two options going forward here: - change how the *structure* of a type is computed before relying on it. i.e. continue considering `for<'a> fn(&'a (), &'a ())` and `for<'a, 'b> fn(&'a (), &'b ())` to be equal, but normalize them to a common representation so that their `TypeId` are also the same. - change how the semantic equality of binders to match the way we compute the structure of types. i.e. `for<'a> fn(&'a (), &'a ())` and `for<'a, 'b> fn(&'a (), &'b ())` still have different `TypeId`s but are now also considered to not be semantically equal. --- Advantages of the first approach: - with the second approach some higher ranked types stop being equal, even though they are subtypes of each other General thoughts: - changing the approach in the future will be breaking - going from first to second may break ordinary type checking, as types which were previously equal are now distinct - going from second to first may break coherence, because previously disjoint impls overlap as the used types are now equal - both of these are quite unlikely. This PR did not result in any crater failures, so this should not matter too much Advantages of the second approach: - the soundness of the first approach requires more non-local reasoning. We have to make sure that changes to subtyping do not cause the representative computation to diverge from semantic equality - e.g. we intend to consider higher ranked implied bounds when subtyping to [fix] https://github.com/rust-lang/rust/issues/25860, I don't know how this will interact and don't feel confident making any prediction here. - computing a representative type is non-trivial and soundness critical, therefore adding complexity to the "core type system" --- This PR goes with the second approach. A crater run did not result in any regressions. I am personally very hesitant about trying the first approach due to the above reasons. It feels like there are more unknowns when going that route. ### Changing the way we equate binders Relating bound variables from different depths already results in a universe error in equate. We therefore only need to make sure that there is 1-to-1 correspondence between bound variables when relating binders. This results in concrete types being structurally equal after anonymizing their bound variables. We implement this by instantiating one of the binder with placeholders and the other with inference variables and then equating the instantiated types. We do so in both directions. More formally, we change the typing rules as follows: ``` for<'r0, .., 'rn> exists<'l0, .., 'ln> LHS<'l0, .., 'ln> <: RHS<'r0, .., 'rn> for<'l0, .., 'ln> exists<'r0, .., 'rn> RHS<'r0, .., 'rn> <: LHS<'l0, .., 'ln> -------------------------------------------------------------------------- for<'l0, .., 'ln> LHS<'l0, .., 'ln> eq for<'r0, .., 'rn> RHS<'r0, .., 'rn> ``` to ``` for<'r0, .., 'rn> exists<'l0, .., 'ln> LHS<'l0, .., 'ln> eq RHS<'r0, .., 'rn> for<'l0, .., 'ln> exists<'r0, .., 'rn> RHS<'r0, .., 'rn> eq LHS<'l0, .., 'ln> -------------------------------------------------------------------------- for<'l0, .., 'ln> LHS<'l0, .., 'ln> eq for<'r0, .., 'rn> RHS<'r0, .., 'rn> ``` --- Fixes #97156 r? `@lcnr`
2024-02-29Change condition in binders to one that is more readableSantiago Pastorino-5/+5
2024-02-29Make infer higher ranked equate use bidirectional subtyping in invariant contextSantiago Pastorino-2/+25
2024-02-29Rollup merge of #121669 - nnethercote:count-stashed-errs-again, r=estebankGuillaume Gomez-16/+0
Count stashed errors again Stashed diagnostics are such a pain. Their "might be emitted, might not" semantics messes with lots of things. #120828 and #121206 made some big changes to how they work, improving some things, but still leaving some problems, as seen by the issues caused by #121206. This PR aims to fix all of them by restricting them in a way that eliminates the "might be emitted, might not" semantics while still allowing 98% of their benefit. Details in the individual commit logs. r? `@oli-obk`
2024-02-29distinguish recursion limit based overflow for diagnosticslcnr-6/+10
also change the number of allowed fixpoint steps to be fixed instead of using the `log` of the total recursion depth.
2024-02-29renaming test casesyukang-6/+6
2024-02-28Improve error messages for generics with default parametersVeera-4/+17
Fixes #120785
2024-02-29Suggest removing superfluous semicolos when statements used as expressionsyukang-0/+97
2024-02-29Overhaul how stashed diagnostics work, again.Nicholas Nethercote-16/+0
Stashed errors used to be counted as errors, but could then be cancelled, leading to `ErrorGuaranteed` soundness holes. #120828 changed that, closing the soundness hole. But it introduced other difficulties because you sometimes have to account for pending stashed errors when making decisions about whether errors have occured/will occur and it's easy to overlook these. This commit aims for a middle ground. - Stashed errors (not warnings) are counted immediately as emitted errors, avoiding the possibility of forgetting to consider them. - The ability to cancel (or downgrade) stashed errors is eliminated, by disallowing the use of `steal_diagnostic` with errors, and introducing the more restrictive methods `try_steal_{modify,replace}_and_emit_err` that can be used instead. Other things: - `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both return `Option<ErrorGuaranteed>`, which enables the removal of two `delayed_bug` calls and one `Ty::new_error_with_message` call. This is possible because we store error guarantees in `DiagCtxt::stashed_diagnostics`. - Storing the guarantees also saves us having to maintain a counter. - Calls to the `stashed_err_count` method are no longer necessary alongside calls to `has_errors`, which is a nice simplification, and eliminates two more `span_delayed_bug` calls and one FIXME comment. - Tests are added for three of the four fixed PRs mentioned below. - `issue-121108.rs`'s output improved slightly, omitting a non-useful error message. Fixes #121451. Fixes #121477. Fixes #121504. Fixes #121508.
2024-02-29Rollup merge of #121743 - compiler-errors:opportunistically-resolve-regions, ↵Matthias Krüger-1/+9
r=jackh726 Opportunistically resolve regions when processing region outlives obligations Due to the matching in `TypeOutlives` being structural, we should attempt to opportunistically resolve regions before processing region obligations. Thanks ``@lcnr`` for finding this. r? lcnr
2024-02-28Opportunistically resolve regions when processing region outlives obligationsMichael Goulet-1/+9
2024-02-28Rename `DiagnosticStyledString` as `DiagStyledString`.Nicholas Nethercote-42/+35
2024-02-28Rename `DiagnosticArg{,Map,Name,Value}` as `DiagArg{,Map,Name,Value}`.Nicholas Nethercote-11/+11
2024-02-28Rename `DiagnosticBuilder` as `Diag`.Nicholas Nethercote-103/+86
Much better! Note that this involves renaming (and updating the value of) `DIAGNOSTIC_BUILDER` in clippy.
2024-02-27when defining opaques, require the hidden type to be well-formedlcnr-1/+18
2024-02-27Avoid a `span_delayed_bug` in `TypeErrCtxt::report_region_errors`.Nicholas Nethercote-31/+31
By returning error guarantees from a few functions it relies on.
2024-02-26always emit `AliasRelate` goals when relating aliaseslcnr-31/+151
Add `StructurallyRelateAliases` to allow instantiating infer vars with rigid aliases. Change `instantiate_query_response` to be infallible in the new solver. This requires canonicalization to not hide any information used by the query, so weaken universe compression. It also modifies `term_is_fully_unconstrained` to allow region inference variables in a higher universe.
2024-02-24Auto merge of #121549 - matthiaskrgr:rollup-1hvu3lb, r=matthiaskrgrbors-0/+8
Rollup of 7 pull requests Successful merges: - #121435 (Account for RPITIT in E0310 explicit lifetime constraint suggestion) - #121490 (Rustdoc: include crate name in links for local primitives) - #121520 (delay cloning of iterator items) - #121522 (check that simd_insert/extract indices are in-bounds) - #121531 (Ignore less tests in debug builds) - #121539 (compiler/rustc_target/src/spec/base/apple/tests.rs: Avoid unnecessary large move) - #121542 (update stdarch) r? `@ghost` `@rustbot` modify labels: rollup
2024-02-24Rollup merge of #121435 - estebank:rpitit-static-119773, r=compiler-errorsMatthias Krüger-0/+8
Account for RPITIT in E0310 explicit lifetime constraint suggestion When given ```rust trait Original { fn f() -> impl Fn(); } trait Erased { fn f(&self) -> Box<dyn Fn()>; } impl<T: Original> Erased for T { fn f(&self) -> Box<dyn Fn()> { Box::new(<T as Original>::f()) } } ``` emit do not emit an invalid suggestion restricting the `Trait::{opaque}` type in a `where` clause: ``` error[E0310]: the associated type `<T as Original>::{opaque#0}` may not live long enough --> $DIR/missing-static-bound-from-impl.rs:11:9 | LL | Box::new(<T as Original>::f()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the associated type `<T as Original>::{opaque#0}` must be valid for the static lifetime... | ...so that the type `impl Fn()` will meet its required lifetime bounds ``` Partially address #119773. Ideally we'd suggest modifying `Erased::f` instead. r? `@compiler-errors`
2024-02-23compiler: clippy::complexity fixesMatthias Krüger-1/+1
2024-02-23Auto merge of #121491 - matthiaskrgr:rollup-wkzqawy, r=matthiaskrgrbors-18/+24
Rollup of 8 pull requests Successful merges: - #121434 (Fix #121208 fallout) - #121471 (When encountering `<&T as Clone>::clone(x)` because `T: Clone`, suggest `#[derive(Clone)]`) - #121476 (remove `llvm.assertions=true` in compiler profile) - #121479 (fix generalizer unsoundness) - #121480 (Fix more #121208 fallout) - #121482 (Allow for a missing `adt_def` in `NamePrivacyVisitor`.) - #121484 (coverage: Use variable name `this` in `CoverageGraph::from_mir`) - #121487 (Explicitly call `emit_stashed_diagnostics`.) r? `@ghost` `@rustbot` modify labels: rollup
2024-02-23Auto merge of #121442 - lcnr:region-var-universe-uwu, r=compiler-errorsbors-52/+85
region unification: update universe of region vars necessary for #119106. see inline comment for why this is necessary r? `@compiler-errors` `@BoxyUwU`
2024-02-23Rollup merge of #121479 - lcnr:fix-generalize, r=compiler-errorsMatthias Krüger-18/+24
fix generalizer unsoundness I ended up getting confused while trying to flip the variances when flipping the order. Should be all right now. This is only exploitable when generalizing if the `ambient_variance` of the relation is `Contravariant`. This can currently only be the case in the NLL generalizer which only rarely generalizes, causing us to miss this regression. Very much an issue with #121462 however.
2024-02-22fix CIlcnr-2/+2
2024-02-22woops, soundly generalizing is hardlcnr-18/+24
I ended up getting confused while trying to flip the variances when flipping the order. Should be all right now
2024-02-22Account for RPITIT in E0310 explicit lifetime constraint suggestionEsteban Küber-0/+8
When given ```rust trait Original { fn f() -> impl Fn(); } trait Erased { fn f(&self) -> Box<dyn Fn()>; } impl<T: Original> Erased for T { fn f(&self) -> Box<dyn Fn()> { Box::new(<T as Original>::f()) } } ``` avoid suggestion to restrict the `Trait::{opaque}` type in a `where` clause: ``` error[E0310]: the associated type `<T as Original>::{opaque#0}` may not live long enough --> $DIR/missing-static-bound-from-impl.rs:11:9 | LL | Box::new(<T as Original>::f()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the associated type `<T as Original>::{opaque#0}` must be valid for the static lifetime... | ...so that the type `impl Fn()` will meet its required lifetime bounds ``` CC #119773.
2024-02-22region unification update universe of region varslcnr-52/+85
2024-02-22freshen: resolve root varslcnr-67/+69
Without doing so we use the same candidate cache entry for `?0: Trait<?1>` and `?0: Trait<?0>`. These goals are different and we must not use the same entry for them.
2024-02-22remove `sub_relations` from infcx, recompute in diagnosticslcnr-144/+115
we don't track them when canonicalizing or when freshening, resulting in instable caching in the old solver, and issues when instantiating query responses in the new one.
2024-02-21Rollup merge of #121206 - nnethercote:top-level-error-handling, r=oli-obkMatthias Krüger-3/+6
Top level error handling The interactions between the following things are surprisingly complicated: - `emit_stashed_diagnostics`, - `flush_delayed`, - normal return vs `abort_if_errors`/`FatalError.raise()` unwinding in the call to the closure in `interface::run_compiler`. This PR disentangles it all. r? `@oli-obk`
2024-02-22Adjust the `has_errors*` methods.Nicholas Nethercote-3/+6
Currently `has_errors` excludes lint errors. This commit changes it to include lint errors. The motivation for this is that for most places it doesn't matter whether lint errors are included or not. But there are multiple places where they must be includes, and only one place where they must not be included. So it makes sense for `has_errors` to do the thing that fits the most situations, and the new `has_errors_excluding_lint_errors` method in the one exceptional place. The same change is made for `err_count`. Annoyingly, this requires the introduction of `err_count_excluding_lint_errs` for one place, to preserve existing error printing behaviour. But I still think the change is worthwhile overall.
2024-02-21Inline NllTypeRelating into its only usage siteMichael Goulet-576/+5
2024-02-21Make TypeRelating more NLL-specificMichael Goulet-9/+9
2024-02-21Yeet QueryTypeRelatingDelegateMichael Goulet-102/+18
2024-02-21Rollup merge of #121359 - lcnr:typesystem-cleanup, r=compiler-errorsLeón Orell Valerian Liehr-64/+83
miscellaneous type system improvements see review comments for rationale r? `@compiler-errors`
2024-02-21Rollup merge of #121328 - ffmancera:ff/verbose_long_type, r=compiler-errorsDylan DPC-0/+1
Make --verbose imply -Z write-long-types-to-disk=no When shortening the type it is necessary to take into account the `--verbose` flag, if it is activated, we must always show the entire type and not write it in a file. Fixes: https://github.com/rust-lang/rust/issues/119130
2024-02-21Rollup merge of #121208 - nnethercote:delayed_bug-to-bug, r=lcnrDylan DPC-5/+3
Convert `delayed_bug`s to `bug`s. I have a suspicion that quite a few delayed bug paths are impossible to reach, so I did an experiment. I converted every `delayed_bug` to a `bug`, ran the full test suite, then converted back every `bug` that was hit. A surprising number were never hit. This is too dangerous to merge. Increased coverage (fuzzing or a crater run) would likely hit more cases. But it might be useful for people to look at and think about which paths are genuinely unreachable. r? `@ghost`
2024-02-21Convert `bug`s back to `delayed_bug`s.Nicholas Nethercote-3/+7
This commit undoes some of the previous commit's mechanical changes, based on human judgment.
2024-02-21Convert `delayed_bug`s to `bug`s.Nicholas Nethercote-11/+5
I have a suspicion that quite a few delayed bug paths are impossible to reach, so I did an experiment. I converted every `delayed_bug` to a `bug`, ran the full test suite, then converted back every `bug` that was hit. A surprising number were never hit. The next commit will convert some more back, based on human judgment.
2024-02-20Suggest using --verbose when writing type to a fileFernando Fernandez Mancera-0/+1
2024-02-20some type system cleanuplcnr-64/+83
2024-02-20Rollup merge of #121344 - fmease:lta-constr-by-input, r=oli-obkMatthias Krüger-3/+3
Expand weak alias types before collecting constrained/referenced late bound regions + refactorings Fixes #114220. Follow-up to #120780. r? `@oli-obk`
2024-02-20Expand weak alias types before collecting constrained and referenced late ↵León Orell Valerian Liehr-3/+3
bound regions