diff options
| author | bors <bors@rust-lang.org> | 2023-01-28 01:05:29 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-01-28 01:05:29 +0000 |
| commit | 6cd6bad51fb34a0d89e97c27814041fe4d0838b5 (patch) | |
| tree | 12df4507b73b7fb3515178a55f0ef54cf2583a8a /compiler/rustc_hir_analysis/src | |
| parent | 7d4df2d30eb342af1ef136d83d70d281f34adcd7 (diff) | |
| parent | d3d626920abf2a4c93bd50640a9d66ce9d5a9009 (diff) | |
| download | rust-6cd6bad51fb34a0d89e97c27814041fe4d0838b5.tar.gz rust-6cd6bad51fb34a0d89e97c27814041fe4d0838b5.zip | |
Auto merge of #101692 - cjgillot:generator-lazy-witness, r=oli-obk
Compute generator saved locals on MIR Generators are currently type-checked by introducing a `witness` type variable, which is unified with a `GeneratorWitness(captured types)` whose purpose is to ensure that the auto traits correctly migrate from the captured types to the `witness` type. This requires computing the captured types on HIR during type-checking, only to re-do it on MIR later. This PR proposes to drop the HIR-based computation, and only keep the MIR one. This is done in 3 steps. 1. During type-checking, the `witness` type variable is never unified. This allows to stall all the obligations that depend on it until the end of type-checking. Then, the stalled obligations are marked as successful, and saved into the typeck results for later verification. 2. At type-checking writeback, `witness` is replaced by `GeneratorWitnessMIR(def_id, substs)`. From this point on, all trait selection involving `GeneratorWitnessMIR` will fetch the MIR-computed locals, similar to what opaque types do. There is no lifetime to be preserved here: we consider all the lifetimes appearing in this witness type to be higher-ranked. 3. After borrowck, the stashed obligations are verified against the actually computed types, in the `check_generator_obligations` query. If any obligation was wrongly marked as fulfilled in step 1, it should be reported here. There are still many issues: - ~I am not too happy having to filter out some locals from the checked bounds, I think this is MIR building that introduces raw pointers polluting the analysis;~ solved by a check specific to static variables. - the diagnostics for captured types don't show where they are used/dropped; - I do not attempt to support chalk. cc `@eholk` `@jyn514` for the drop-tracking work r? `@oli-obk` as you warned me of potential unsoundness
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
4 files changed, 43 insertions, 9 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 6c7482b40c3..c89db538aa6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -14,7 +14,7 @@ use rustc_hir::{ItemKind, Node, PathSegment}; use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; -use rustc_infer::traits::Obligation; +use rustc_infer::traits::{Obligation, TraitEngineExt as _}; use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; use rustc_middle::middle::stability::EvalResult; @@ -28,7 +28,7 @@ use rustc_span::{self, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCtxt}; +use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _}; use std::ops::ControlFlow; @@ -1460,7 +1460,8 @@ fn opaque_type_cycle_error( for def_id in visitor.opaques { let ty_span = tcx.def_span(def_id); if !seen.contains(&ty_span) { - err.span_label(ty_span, &format!("returning this opaque type `{ty}`")); + let descr = if ty.is_impl_trait() { "opaque " } else { "" }; + err.span_label(ty_span, &format!("returning this {descr}type `{ty}`")); seen.insert(ty_span); } err.span_label(sp, &format!("returning here with type `{ty}`")); @@ -1507,3 +1508,34 @@ fn opaque_type_cycle_error( } err.emit() } + +pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { + debug_assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); + debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator)); + + let typeck = tcx.typeck(def_id); + let param_env = tcx.param_env(def_id); + + let generator_interior_predicates = &typeck.generator_interior_predicates[&def_id]; + debug!(?generator_interior_predicates); + + let infcx = tcx + .infer_ctxt() + // typeck writeback gives us predicates with their regions erased. + // As borrowck already has checked lifetimes, we do not need to do it again. + .ignoring_regions() + // Bind opaque types to `def_id` as they should have been checked by borrowck. + .with_opaque_type_inference(DefiningAnchor::Bind(def_id)) + .build(); + + let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); + for (predicate, cause) in generator_interior_predicates { + let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + let errors = fulfillment_cx.select_all_or_error(&infcx); + debug!(?errors); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors, None); + } +} diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 2f2ee702837..bec693439a4 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -105,6 +105,7 @@ pub fn provide(providers: &mut Providers) { region_scope_tree, collect_return_position_impl_trait_in_trait_tys, compare_impl_const: compare_impl_item::compare_impl_const_raw, + check_generator_obligations: check::check_generator_obligations, ..*providers }; } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index dfb98240943..c1b0237b2d1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -240,6 +240,7 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => { diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 2cd2b6a5f76..a1872822d36 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -295,12 +295,12 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // types, where we use Error as the Self type } - ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Bound(..) | ty::Infer(..) => { - bug!( - "unexpected type encountered in \ - variance inference: {}", - ty - ); + ty::Placeholder(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Bound(..) + | ty::Infer(..) => { + bug!("unexpected type encountered in variance inference: {}", ty); } } } |
