Skip to content

merge TypeChecker and TypeVerifier #138357

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 13, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 26 additions & 28 deletions compiler/rustc_borrowck/src/type_check/input_output.rs
Original file line number Diff line number Diff line change
@@ -24,9 +24,9 @@ use crate::universal_regions::DefiningTy;
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
/// Check explicit closure signature annotation,
/// e.g., `|x: FxIndexMap<_, &'static u32>| ...`.
#[instrument(skip(self, body), level = "debug")]
pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
let mir_def_id = body.source.def_id().expect_local();
#[instrument(skip(self), level = "debug")]
pub(super) fn check_signature_annotation(&mut self) {
let mir_def_id = self.body.source.def_id().expect_local();

if !self.tcx().is_closure_like(mir_def_id.to_def_id()) {
return;
@@ -38,9 +38,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// (e.g., the `_` in the code above) with fresh variables.
// Then replace the bound items in the fn sig with fresh variables,
// so that they represent the view from "inside" the closure.
let user_provided_sig = self.instantiate_canonical(body.span, &user_provided_poly_sig);
let user_provided_sig = self.instantiate_canonical(self.body.span, &user_provided_poly_sig);
let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
body.span,
self.body.span,
BoundRegionConversionTime::FnCall,
user_provided_sig,
);
@@ -66,12 +66,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Ty::new_tup(self.tcx(), user_provided_sig.inputs()),
args.tupled_upvars_ty(),
args.coroutine_captures_by_ref_ty(),
self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(body.span), || {
RegionCtxt::Unknown
}),
self.infcx
.next_region_var(RegionVariableOrigin::MiscVariable(self.body.span), || {
RegionCtxt::Unknown
}),
);

let next_ty_var = || self.infcx.next_ty_var(body.span);
let next_ty_var = || self.infcx.next_ty_var(self.body.span);
let output_ty = Ty::new_coroutine(
self.tcx(),
self.tcx().coroutine_for_closure(mir_def_id),
@@ -107,9 +108,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip_eq(
// In MIR, closure args begin with an implicit `self`.
// Also, coroutines have a resume type which may be implicitly `()`.
body.args_iter()
self.body
.args_iter()
.skip(1 + if is_coroutine_with_implicit_resume_ty { 1 } else { 0 })
.map(|local| &body.local_decls[local]),
.map(|local| &self.body.local_decls[local]),
) {
self.ascribe_user_type_skip_wf(
arg_decl.ty,
@@ -119,20 +121,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}

// If the user explicitly annotated the output type, enforce it.
let output_decl = &body.local_decls[RETURN_PLACE];
let output_decl = &self.body.local_decls[RETURN_PLACE];
self.ascribe_user_type_skip_wf(
output_decl.ty,
ty::UserType::new(ty::UserTypeKind::Ty(user_provided_sig.output())),
output_decl.source_info.span,
);
}

#[instrument(skip(self, body), level = "debug")]
pub(super) fn equate_inputs_and_outputs(
&mut self,
body: &Body<'tcx>,
normalized_inputs_and_output: &[Ty<'tcx>],
) {
#[instrument(skip(self), level = "debug")]
pub(super) fn equate_inputs_and_outputs(&mut self, normalized_inputs_and_output: &[Ty<'tcx>]) {
let (&normalized_output_ty, normalized_input_tys) =
normalized_inputs_and_output.split_last().unwrap();

@@ -141,36 +139,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {

// Equate expected input tys with those in the MIR.
for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
if argument_index + 1 >= body.local_decls.len() {
if argument_index + 1 >= self.body.local_decls.len() {
self.tcx()
.dcx()
.span_bug(body.span, "found more normalized_input_ty than local_decls");
.span_bug(self.body.span, "found more normalized_input_ty than local_decls");
}

// In MIR, argument N is stored in local N+1.
let local = Local::from_usize(argument_index + 1);

let mir_input_ty = body.local_decls[local].ty;
let mir_input_ty = self.body.local_decls[local].ty;

let mir_input_span = body.local_decls[local].source_info.span;
let mir_input_span = self.body.local_decls[local].source_info.span;
self.equate_normalized_input_or_output(
normalized_input_ty,
mir_input_ty,
mir_input_span,
);
}

if let Some(mir_yield_ty) = body.yield_ty() {
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
if let Some(mir_yield_ty) = self.body.yield_ty() {
let yield_span = self.body.local_decls[RETURN_PLACE].source_info.span;
self.equate_normalized_input_or_output(
self.universal_regions.yield_ty.unwrap(),
mir_yield_ty,
yield_span,
);
}

if let Some(mir_resume_ty) = body.resume_ty() {
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
if let Some(mir_resume_ty) = self.body.resume_ty() {
let yield_span = self.body.local_decls[RETURN_PLACE].source_info.span;
self.equate_normalized_input_or_output(
self.universal_regions.resume_ty.unwrap(),
mir_resume_ty,
@@ -179,8 +177,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}

// Return types are a bit more complex. They may contain opaque `impl Trait` types.
let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
let output_span = body.local_decls[RETURN_PLACE].source_info.span;
let mir_output_ty = self.body.local_decls[RETURN_PLACE].ty;
let output_span = self.body.local_decls[RETURN_PLACE].source_info.span;
self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span);
}

20 changes: 6 additions & 14 deletions compiler/rustc_borrowck/src/type_check/liveness/mod.rs
Original file line number Diff line number Diff line change
@@ -31,7 +31,6 @@ mod trace;
/// performed before
pub(super) fn generate<'a, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>,
location_map: &DenseLocationMap,
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
move_data: &MoveData<'tcx>,
@@ -51,23 +50,16 @@ pub(super) fn generate<'a, 'tcx>(
// We do record these regions in the polonius context, since they're used to differentiate
// relevant and boring locals, which is a key distinction used later in diagnostics.
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
let (_, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
let (_, boring_locals) =
compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);
typeck.polonius_liveness.as_mut().unwrap().boring_nll_locals =
boring_locals.into_iter().collect();
free_regions = typeck.universal_regions.universal_regions_iter().collect();
}
let (relevant_live_locals, boring_locals) =
compute_relevant_live_locals(typeck.tcx(), &free_regions, body);

trace::trace(
typeck,
body,
location_map,
flow_inits,
move_data,
relevant_live_locals,
boring_locals,
);
compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);

trace::trace(typeck, location_map, flow_inits, move_data, relevant_live_locals, boring_locals);

// Mark regions that should be live where they appear within rvalues or within a call: like
// args, regions, and types.
@@ -76,7 +68,7 @@ pub(super) fn generate<'a, 'tcx>(
&mut typeck.constraints.liveness_constraints,
&typeck.universal_regions,
&mut typeck.polonius_liveness,
body,
typeck.body,
);
}

42 changes: 21 additions & 21 deletions compiler/rustc_borrowck/src/type_check/liveness/trace.rs
Original file line number Diff line number Diff line change
@@ -39,17 +39,15 @@ use crate::type_check::{NormalizeLocation, TypeChecker};
/// this respects `#[may_dangle]` annotations).
pub(super) fn trace<'a, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>,
location_map: &DenseLocationMap,
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
move_data: &MoveData<'tcx>,
relevant_live_locals: Vec<Local>,
boring_locals: Vec<Local>,
) {
let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, body);
let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, typeck.body);
let cx = LivenessContext {
typeck,
body,
flow_inits,
location_map,
local_use_map,
@@ -69,14 +67,13 @@ pub(super) fn trace<'a, 'tcx>(
/// Contextual state for the type-liveness coroutine.
struct LivenessContext<'a, 'typeck, 'b, 'tcx> {
/// Current type-checker, giving us our inference context etc.
///
/// This also stores the body we're currently analyzing.
typeck: &'a mut TypeChecker<'typeck, 'tcx>,

/// Defines the `PointIndex` mapping
location_map: &'a DenseLocationMap,

/// MIR we are analyzing.
body: &'a Body<'tcx>,

/// Mapping to/from the various indices used for initialization tracking.
move_data: &'a MoveData<'tcx>,

@@ -139,7 +136,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
self.compute_use_live_points_for(local);
self.compute_drop_live_points_for(local);

let local_ty = self.cx.body.local_decls[local].ty;
let local_ty = self.cx.body().local_decls[local].ty;

if !self.use_live_at.is_empty() {
self.cx.add_use_live_facts_for(local_ty, &self.use_live_at);
@@ -164,16 +161,16 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
/// and can therefore safely be dropped.
fn dropck_boring_locals(&mut self, boring_locals: Vec<Local>) {
for local in boring_locals {
let local_ty = self.cx.body.local_decls[local].ty;
let local_span = self.cx.body.local_decls[local].source_info.span;
let local_ty = self.cx.body().local_decls[local].ty;
let local_span = self.cx.body().local_decls[local].source_info.span;
let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({
let typeck = &self.cx.typeck;
move || LivenessContext::compute_drop_data(typeck, local_ty, local_span)
});

drop_data.dropck_result.report_overflows(
self.cx.typeck.infcx.tcx,
self.cx.body.local_decls[local].source_info.span,
self.cx.typeck.body.local_decls[local].source_info.span,
local_ty,
);
}
@@ -202,7 +199,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
.var_dropped_at
.iter()
.filter_map(|&(local, location_index)| {
let local_ty = self.cx.body.local_decls[local].ty;
let local_ty = self.cx.body().local_decls[local].ty;
if relevant_live_locals.contains(&local) || !local_ty.has_free_regions() {
return None;
}
@@ -278,9 +275,9 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {

let block = self.cx.location_map.to_location(block_start).block;
self.stack.extend(
self.cx.body.basic_blocks.predecessors()[block]
self.cx.body().basic_blocks.predecessors()[block]
.iter()
.map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
.map(|&pred_bb| self.cx.body().terminator_loc(pred_bb))
.map(|pred_loc| self.cx.location_map.point_from_location(pred_loc)),
);
}
@@ -305,7 +302,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
// Find the drops where `local` is initialized.
for drop_point in self.cx.local_use_map.drops(local) {
let location = self.cx.location_map.to_location(drop_point);
debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,);
debug_assert_eq!(self.cx.body().terminator_loc(location.block), location,);

if self.cx.initialized_at_terminator(location.block, mpi)
&& self.drop_live_at.insert(drop_point)
@@ -351,7 +348,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
// block. One of them may be either a definition or use
// live point.
let term_location = self.cx.location_map.to_location(term_point);
debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,);
debug_assert_eq!(self.cx.body().terminator_loc(term_location.block), term_location,);
let block = term_location.block;
let entry_point = self.cx.location_map.entry_point(term_location.block);
for p in (entry_point..term_point).rev() {
@@ -376,7 +373,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
}
}

let body = self.cx.body;
let body = self.cx.typeck.body;
for &pred_block in body.basic_blocks.predecessors()[block].iter() {
debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,);

@@ -403,7 +400,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
continue;
}

let pred_term_loc = self.cx.body.terminator_loc(pred_block);
let pred_term_loc = self.cx.body().terminator_loc(pred_block);
let pred_term_point = self.cx.location_map.point_from_location(pred_term_loc);

// If the terminator of this predecessor either *assigns*
@@ -463,6 +460,9 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
}

impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
fn body(&self) -> &Body<'tcx> {
self.typeck.body
}
/// Returns `true` if the local variable (or some part of it) is initialized at the current
/// cursor position. Callers should call one of the `seek` methods immediately before to point
/// the cursor to the desired location.
@@ -481,7 +481,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
/// DROP of some local variable will have an effect -- note that
/// drops, as they may unwind, are always terminators.
fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
self.flow_inits.seek_before_primary_effect(self.body.terminator_loc(block));
self.flow_inits.seek_before_primary_effect(self.body().terminator_loc(block));
self.initialized_at_curr_loc(mpi)
}

@@ -491,7 +491,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
/// **Warning:** Does not account for the result of `Call`
/// instructions.
fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
self.flow_inits.seek_after_primary_effect(self.body.terminator_loc(block));
self.flow_inits.seek_after_primary_effect(self.body().terminator_loc(block));
self.initialized_at_curr_loc(mpi)
}

@@ -526,7 +526,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
values::pretty_print_points(self.location_map, live_at.iter()),
);

let local_span = self.body.local_decls()[dropped_local].source_info.span;
let local_span = self.body().local_decls()[dropped_local].source_info.span;
let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
let typeck = &self.typeck;
move || Self::compute_drop_data(typeck, dropped_ty, local_span)
@@ -544,7 +544,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {

drop_data.dropck_result.report_overflows(
self.typeck.infcx.tcx,
self.body.source_info(*drop_locations.first().unwrap()).span,
self.typeck.body.source_info(*drop_locations.first().unwrap()).span,
dropped_ty,
);

2,289 changes: 1,085 additions & 1,204 deletions compiler/rustc_borrowck/src/type_check/mod.rs

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions tests/ui/consts/const-unsized.stderr
Original file line number Diff line number Diff line change
@@ -58,18 +58,18 @@ error[E0507]: cannot move out of a shared reference
LL | static STATIC_BAR: str = *"bar";
| ^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait

error[E0161]: cannot move a value of type `str`
--> $DIR/const-unsized.rs:20:48
|
LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
| ^^^^^^^^^ the size of `str` cannot be statically determined

error[E0161]: cannot move a value of type `dyn Debug + Sync`
--> $DIR/const-unsized.rs:20:38
|
LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
| ^^^^^^^ the size of `dyn Debug + Sync` cannot be statically determined

error[E0161]: cannot move a value of type `str`
--> $DIR/const-unsized.rs:20:48
|
LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
| ^^^^^^^^^ the size of `str` cannot be statically determined

error: aborting due to 10 previous errors

Some errors have detailed explanations: E0161, E0277, E0507.
4 changes: 2 additions & 2 deletions tests/ui/traits/trait-upcasting/type-checking-test-4.stderr
Original file line number Diff line number Diff line change
@@ -7,12 +7,12 @@ LL | let _ = x as &dyn Bar<'static, 'a>; // Error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/type-checking-test-4.rs:22:18
--> $DIR/type-checking-test-4.rs:22:13
|
LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
| -- lifetime `'a` defined here
LL | let _ = x as &dyn Bar<'a, 'static>; // Error
| ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/type-checking-test-4.rs:28:5