Skip to content

Commit 17ffbc8

Browse files
committed
Auto merge of #138785 - lcnr:typing-mode-borrowck, r=compiler-errors,oli-obk
add `TypingMode::Borrowck` Shares the first commit with #138499, doesn't really matter which PR to land first 😊 😁 Introduces `TypingMode::Borrowck` which unlike `TypingMode::Analysis`, uses the hidden type computed by HIR typeck as the initial value of opaques instead of an unconstrained infer var. This is a part of rust-lang/types-team#129. Using this new `TypingMode` is unfortunately a breaking change for now, see tests/ui/impl-trait/non-defining-uses/as-projection-term.rs. Using an inference variable as the initial value results in non-defining uses in the defining scope. We therefore only enable it if with `-Znext-solver=globally` or `-Ztyping-mode-borrowck` To do that the PR contains the following changes: - `TypeckResults::concrete_opaque_type` are already mapped to the definition of the opaque type - writeback now checks that the non-lifetime parameters of the opaque are universal - for this, `fn check_opaque_type_parameter_valid` is moved from `rustc_borrowck` to `rustc_trait_selection` - we add a new `query type_of_opaque_hir_typeck` which, using the same visitors as MIR typeck, attempts to merge the hidden types from HIR typeck from all defining scopes - done by adding a `DefiningScopeKind` flag to toggle between using borrowck and HIR typeck - the visitors stop checking that the MIR type matches the HIR type. This is trivial as the HIR type are now used as the initial hidden types of the opaque. This check is useful as a safeguard when not using `TypingMode::Borrowck`, but adding it to the new structure is annoying and it's not soundness critical, so I intend to not add it back. - add a `TypingMode::Borrowck` which behaves just like `TypingMode::Analysis` except when normalizing opaque types - it uses `type_of_opaque_hir_typeck(opaque)` as the initial value after replacing its regions with new inference vars - it uses structural lookup in the new solver fixes #112201, fixes #132335, fixes #137751 r? `@compiler-errors` `@oli-obk`
2 parents 5337252 + 509a144 commit 17ffbc8

File tree

136 files changed

+1063
-987
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

136 files changed

+1063
-987
lines changed

compiler/rustc_borrowck/messages.ftl

-7
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,6 @@ borrowck_opaque_type_lifetime_mismatch =
162162
.prev_lifetime_label = lifetime `{$prev}` previously used here
163163
.note = if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
164164
165-
borrowck_opaque_type_non_generic_param =
166-
expected generic {$kind} parameter, found `{$ty}`
167-
.label = {STREQ($ty, "'static") ->
168-
[true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
169-
*[other] this generic parameter must be used with a generic {$kind} parameter
170-
}
171-
172165
borrowck_partial_var_move_by_use_in_closure =
173166
variable {$is_partial ->
174167
[true] partially moved

compiler/rustc_borrowck/src/lib.rs

+7-31
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use rustc_infer::infer::{
3535
};
3636
use rustc_middle::mir::*;
3737
use rustc_middle::query::Providers;
38-
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode, fold_regions};
38+
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
3939
use rustc_middle::{bug, span_bug};
4040
use rustc_mir_dataflow::impls::{
4141
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
@@ -171,12 +171,6 @@ fn do_mir_borrowck<'tcx>(
171171
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
172172
let body = &body_owned; // no further changes
173173

174-
// FIXME(-Znext-solver): A bit dubious that we're only registering
175-
// predefined opaques in the typeck root.
176-
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
177-
infcx.register_predefined_opaques_for_next_solver(def);
178-
}
179-
180174
let location_table = PoloniusLocationTable::new(body);
181175

182176
let move_data = MoveData::gather_moves(body, tcx, |_| true);
@@ -431,7 +425,12 @@ pub(crate) struct BorrowckInferCtxt<'tcx> {
431425

432426
impl<'tcx> BorrowckInferCtxt<'tcx> {
433427
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
434-
let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id));
428+
let typing_mode = if tcx.use_typing_mode_borrowck() {
429+
TypingMode::borrowck(tcx, def_id)
430+
} else {
431+
TypingMode::analysis_in_body(tcx, def_id)
432+
};
433+
let infcx = tcx.infer_ctxt().build(typing_mode);
435434
let param_env = tcx.param_env(def_id);
436435
BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
437436
}
@@ -478,29 +477,6 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
478477

479478
next_region
480479
}
481-
482-
/// With the new solver we prepopulate the opaque type storage during
483-
/// MIR borrowck with the hidden types from HIR typeck. This is necessary
484-
/// to avoid ambiguities as earlier goals can rely on the hidden type
485-
/// of an opaque which is only constrained by a later goal.
486-
fn register_predefined_opaques_for_next_solver(&self, def_id: LocalDefId) {
487-
let tcx = self.tcx;
488-
// OK to use the identity arguments for each opaque type key, since
489-
// we remap opaques from HIR typeck back to their definition params.
490-
for data in tcx.typeck(def_id).concrete_opaque_types.iter().map(|(k, v)| (*k, *v)) {
491-
// HIR typeck did not infer the regions of the opaque, so we instantiate
492-
// them with fresh inference variables.
493-
let (key, hidden_ty) = fold_regions(tcx, data, |_, _| {
494-
self.next_nll_region_var_in_universe(
495-
NllRegionVariableOrigin::Existential { from_forall: false },
496-
ty::UniverseIndex::ROOT,
497-
)
498-
});
499-
500-
let prev = self.register_hidden_type_in_storage(key, hidden_ty);
501-
assert_eq!(prev, None);
502-
}
503-
}
504480
}
505481

506482
impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+16-167
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
use rustc_data_structures::fx::FxIndexMap;
2-
use rustc_errors::ErrorGuaranteed;
3-
use rustc_hir::OpaqueTyOrigin;
4-
use rustc_hir::def_id::LocalDefId;
5-
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
6-
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
2+
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
73
use rustc_macros::extension;
84
use rustc_middle::ty::{
9-
self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
10-
TypeVisitableExt, TypingMode, fold_regions,
5+
self, DefiningScopeKind, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
6+
TypeVisitableExt, fold_regions,
117
};
128
use rustc_span::Span;
13-
use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
14-
use rustc_trait_selection::traits::ObligationCtxt;
9+
use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
1510
use tracing::{debug, instrument};
1611

1712
use super::RegionInferenceContext;
1813
use crate::opaque_types::ConcreteOpaqueTypes;
19-
use crate::session_diagnostics::{LifetimeMismatchOpaqueParam, NonGenericOpaqueTypeParam};
14+
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
2015
use crate::universal_regions::RegionClassification;
2116

2217
impl<'tcx> RegionInferenceContext<'tcx> {
@@ -272,14 +267,21 @@ impl<'tcx> InferCtxt<'tcx> {
272267
return Ty::new_error(self.tcx, e);
273268
}
274269

275-
if let Err(guar) =
276-
check_opaque_type_parameter_valid(self, opaque_type_key, instantiated_ty.span)
277-
{
270+
if let Err(guar) = check_opaque_type_parameter_valid(
271+
self,
272+
opaque_type_key,
273+
instantiated_ty.span,
274+
DefiningScopeKind::MirBorrowck,
275+
) {
278276
return Ty::new_error(self.tcx, guar);
279277
}
280278

281279
let definition_ty = instantiated_ty
282-
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
280+
.remap_generic_params_to_declaration_params(
281+
opaque_type_key,
282+
self.tcx,
283+
DefiningScopeKind::MirBorrowck,
284+
)
283285
.ty;
284286

285287
if let Err(e) = definition_ty.error_reported() {
@@ -289,156 +291,3 @@ impl<'tcx> InferCtxt<'tcx> {
289291
definition_ty
290292
}
291293
}
292-
293-
/// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter].
294-
///
295-
/// [rustc-dev-guide chapter]:
296-
/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
297-
fn check_opaque_type_parameter_valid<'tcx>(
298-
infcx: &InferCtxt<'tcx>,
299-
opaque_type_key: OpaqueTypeKey<'tcx>,
300-
span: Span,
301-
) -> Result<(), ErrorGuaranteed> {
302-
let tcx = infcx.tcx;
303-
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
304-
let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
305-
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
306-
307-
for (i, arg) in opaque_type_key.iter_captured_args(tcx) {
308-
let arg_is_param = match arg.unpack() {
309-
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
310-
GenericArgKind::Lifetime(lt) => {
311-
matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_))
312-
|| (lt.is_static() && opaque_env.param_equal_static(i))
313-
}
314-
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
315-
};
316-
317-
if arg_is_param {
318-
// Register if the same lifetime appears multiple times in the generic args.
319-
// There is an exception when the opaque type *requires* the lifetimes to be equal.
320-
// See [rustc-dev-guide chapter] § "An exception to uniqueness rule".
321-
let seen_where = seen_params.entry(arg).or_default();
322-
if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) {
323-
seen_where.push(i);
324-
}
325-
} else {
326-
// Prevent `fn foo() -> Foo<u32>` from being defining.
327-
let opaque_param = opaque_generics.param_at(i, tcx);
328-
let kind = opaque_param.kind.descr();
329-
330-
opaque_env.param_is_error(i)?;
331-
332-
return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam {
333-
ty: arg,
334-
kind,
335-
span,
336-
param_span: tcx.def_span(opaque_param.def_id),
337-
}));
338-
}
339-
}
340-
341-
for (_, indices) in seen_params {
342-
if indices.len() > 1 {
343-
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
344-
let spans: Vec<_> = indices
345-
.into_iter()
346-
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
347-
.collect();
348-
#[allow(rustc::diagnostic_outside_of_impl)]
349-
#[allow(rustc::untranslatable_diagnostic)]
350-
return Err(infcx
351-
.dcx()
352-
.struct_span_err(span, "non-defining opaque type use in defining scope")
353-
.with_span_note(spans, format!("{descr} used multiple times"))
354-
.emit());
355-
}
356-
}
357-
358-
Ok(())
359-
}
360-
361-
/// Computes if an opaque type requires a lifetime parameter to be equal to
362-
/// another one or to the `'static` lifetime.
363-
/// These requirements are derived from the explicit and implied bounds.
364-
struct LazyOpaqueTyEnv<'tcx> {
365-
tcx: TyCtxt<'tcx>,
366-
def_id: LocalDefId,
367-
368-
/// Equal parameters will have the same name. Computed Lazily.
369-
/// Example:
370-
/// `type Opaque<'a: 'static, 'b: 'c, 'c: 'b> = impl Sized;`
371-
/// Identity args: `['a, 'b, 'c]`
372-
/// Canonical args: `['static, 'b, 'b]`
373-
canonical_args: std::cell::OnceCell<ty::GenericArgsRef<'tcx>>,
374-
}
375-
376-
impl<'tcx> LazyOpaqueTyEnv<'tcx> {
377-
fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
378-
Self { tcx, def_id, canonical_args: std::cell::OnceCell::new() }
379-
}
380-
381-
fn param_equal_static(&self, param_index: usize) -> bool {
382-
self.get_canonical_args()[param_index].expect_region().is_static()
383-
}
384-
385-
fn params_equal(&self, param1: usize, param2: usize) -> bool {
386-
let canonical_args = self.get_canonical_args();
387-
canonical_args[param1] == canonical_args[param2]
388-
}
389-
390-
fn param_is_error(&self, param_index: usize) -> Result<(), ErrorGuaranteed> {
391-
self.get_canonical_args()[param_index].error_reported()
392-
}
393-
394-
fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> {
395-
if let Some(&canonical_args) = self.canonical_args.get() {
396-
return canonical_args;
397-
}
398-
399-
let &Self { tcx, def_id, .. } = self;
400-
let origin = tcx.local_opaque_ty_origin(def_id);
401-
let parent = match origin {
402-
OpaqueTyOrigin::FnReturn { parent, .. }
403-
| OpaqueTyOrigin::AsyncFn { parent, .. }
404-
| OpaqueTyOrigin::TyAlias { parent, .. } => parent,
405-
};
406-
let param_env = tcx.param_env(parent);
407-
let args = GenericArgs::identity_for_item(tcx, parent).extend_to(
408-
tcx,
409-
def_id.to_def_id(),
410-
|param, _| {
411-
tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()
412-
},
413-
);
414-
415-
// FIXME(#132279): It feels wrong to use `non_body_analysis` here given that we're
416-
// in a body here.
417-
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
418-
let ocx = ObligationCtxt::new(&infcx);
419-
420-
let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| {
421-
tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds");
422-
Default::default()
423-
});
424-
let outlives_env = OutlivesEnvironment::new(&infcx, parent, param_env, wf_tys);
425-
426-
let mut seen = vec![tcx.lifetimes.re_static];
427-
let canonical_args = fold_regions(tcx, args, |r1, _| {
428-
if r1.is_error() {
429-
r1
430-
} else if let Some(&r2) = seen.iter().find(|&&r2| {
431-
let free_regions = outlives_env.free_region_map();
432-
free_regions.sub_free_regions(tcx, r1, r2)
433-
&& free_regions.sub_free_regions(tcx, r2, r1)
434-
}) {
435-
r2
436-
} else {
437-
seen.push(r1);
438-
r1
439-
}
440-
});
441-
self.canonical_args.set(canonical_args).unwrap();
442-
canonical_args
443-
}
444-
}

compiler/rustc_borrowck/src/session_diagnostics.rs

-11
Original file line numberDiff line numberDiff line change
@@ -294,17 +294,6 @@ pub(crate) struct MoveBorrow<'a> {
294294
pub borrow_span: Span,
295295
}
296296

297-
#[derive(Diagnostic)]
298-
#[diag(borrowck_opaque_type_non_generic_param, code = E0792)]
299-
pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
300-
pub ty: GenericArg<'tcx>,
301-
pub kind: &'a str,
302-
#[primary_span]
303-
pub span: Span,
304-
#[label]
305-
pub param_span: Span,
306-
}
307-
308297
#[derive(Diagnostic)]
309298
#[diag(borrowck_opaque_type_lifetime_mismatch)]
310299
pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> {

compiler/rustc_hir_analysis/src/collect.rs

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) {
6161
*providers = Providers {
6262
type_of: type_of::type_of,
6363
type_of_opaque: type_of::type_of_opaque,
64+
type_of_opaque_hir_typeck: type_of::type_of_opaque_hir_typeck,
6465
type_alias_is_lazy: type_of::type_alias_is_lazy,
6566
item_bounds: item_bounds::item_bounds,
6667
explicit_item_bounds: item_bounds::explicit_item_bounds,

0 commit comments

Comments
 (0)