diff options
Diffstat (limited to 'compiler/rustc_mir_build')
23 files changed, 1613 insertions, 259 deletions
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 4ad3343d3..f24b165d7 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -11,7 +11,6 @@ tracing = "0.1" either = "1" rustc_middle = { path = "../rustc_middle" } rustc_apfloat = { path = "../rustc_apfloat" } -rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_mir_build/locales/en-US.ftl b/compiler/rustc_mir_build/locales/en-US.ftl new file mode 100644 index 000000000..93e7fb330 --- /dev/null +++ b/compiler/rustc_mir_build/locales/en-US.ftl @@ -0,0 +1,382 @@ +mir_build_unconditional_recursion = function cannot return without recursing + .label = cannot return without recursing + .help = a `loop` may express intention better if this is on purpose + +mir_build_unconditional_recursion_call_site_label = recursive call site + +mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe = + call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133) + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless = + call to unsafe function is unsafe and requires unsafe block (error E0133) + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe = + use of inline assembly is unsafe and requires unsafe block (error E0133) + .note = inline assembly is entirely unchecked and can cause undefined behavior + .label = use of inline assembly + +mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe = + initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe + block (error E0133) + .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior + .label = initializing type with `rustc_layout_scalar_valid_range` attr + +mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe = + use of mutable static is unsafe and requires unsafe block (error E0133) + .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + .label = use of mutable static + +mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe = + use of extern static is unsafe and requires unsafe block (error E0133) + .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + .label = use of extern static + +mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe = + dereference of raw pointer is unsafe and requires unsafe block (error E0133) + .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + .label = dereference of raw pointer + +mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe = + access to union field is unsafe and requires unsafe block (error E0133) + .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior + .label = access to union field + +mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe = + mutation of layout constrained field is unsafe and requires unsafe block (error E0133) + .note = mutating layout constrained fields cannot statically be checked for valid values + .label = mutation of layout constrained field + +mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe = + borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133) + .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values + .label = borrow of layout constrained field with interior mutability + +mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe = + call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) + .note = can only be called if the required target features are available + .label = call to function with `#[target_feature]` + +mir_build_call_to_unsafe_fn_requires_unsafe = + call to unsafe function `{$function}` is unsafe and requires unsafe block + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_call_to_unsafe_fn_requires_unsafe_nameless = + call to unsafe function is unsafe and requires unsafe block + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + call to unsafe function `{$function}` is unsafe and requires unsafe function or block + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed = + call to unsafe function is unsafe and requires unsafe function or block + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_inline_assembly_requires_unsafe = + use of inline assembly is unsafe and requires unsafe block + .note = inline assembly is entirely unchecked and can cause undefined behavior + .label = use of inline assembly + +mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of inline assembly is unsafe and requires unsafe function or block + .note = inline assembly is entirely unchecked and can cause undefined behavior + .label = use of inline assembly + +mir_build_initializing_type_with_requires_unsafe = + initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block + .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior + .label = initializing type with `rustc_layout_scalar_valid_range` attr + +mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block + .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior + .label = initializing type with `rustc_layout_scalar_valid_range` attr + +mir_build_mutable_static_requires_unsafe = + use of mutable static is unsafe and requires unsafe block + .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + .label = use of mutable static + +mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of mutable static is unsafe and requires unsafe function or block + .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + .label = use of mutable static + +mir_build_extern_static_requires_unsafe = + use of extern static is unsafe and requires unsafe block + .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + .label = use of extern static + +mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of extern static is unsafe and requires unsafe function or block + .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + .label = use of extern static + +mir_build_deref_raw_pointer_requires_unsafe = + dereference of raw pointer is unsafe and requires unsafe block + .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + .label = dereference of raw pointer + +mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + dereference of raw pointer is unsafe and requires unsafe function or block + .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + .label = dereference of raw pointer + +mir_build_union_field_requires_unsafe = + access to union field is unsafe and requires unsafe block + .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior + .label = access to union field + +mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + access to union field is unsafe and requires unsafe function or block + .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior + .label = access to union field + +mir_build_mutation_of_layout_constrained_field_requires_unsafe = + mutation of layout constrained field is unsafe and requires unsafe block + .note = mutating layout constrained fields cannot statically be checked for valid values + .label = mutation of layout constrained field + +mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + mutation of layout constrained field is unsafe and requires unsafe function or block + .note = mutating layout constrained fields cannot statically be checked for valid values + .label = mutation of layout constrained field + +mir_build_borrow_of_layout_constrained_field_requires_unsafe = + borrow of layout constrained field with interior mutability is unsafe and requires unsafe block + .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values + .label = borrow of layout constrained field with interior mutability + +mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block + .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values + .label = borrow of layout constrained field with interior mutability + +mir_build_call_to_fn_with_requires_unsafe = + call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block + .note = can only be called if the required target features are available + .label = call to function with `#[target_feature]` + +mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block + .note = can only be called if the required target features are available + .label = call to function with `#[target_feature]` + +mir_build_unused_unsafe = unnecessary `unsafe` block + .label = unnecessary `unsafe` block + +mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block +mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn + +mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty + .def_note = `{$peeled_ty}` defined here + .type_note = the matched value is of type `{$ty}` + .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive + .reference_note = references are always considered inhabited + .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +mir_build_static_in_pattern = statics cannot be referenced in patterns + +mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns + +mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns + +mir_build_non_const_path = runtime values cannot be referenced in patterns + +mir_build_unreachable_pattern = unreachable pattern + .label = unreachable pattern + .catchall_label = matches any value + +mir_build_const_pattern_depends_on_generic_parameter = + constant pattern depends on a generic parameter + +mir_build_could_not_eval_const_pattern = could not evaluate constant pattern + +mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = + lower range bound must be less than or equal to upper + .label = lower bound larger than upper bound + .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. + +mir_build_literal_in_range_out_of_bounds = + literal out of range for `{$ty}` + .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}` + +mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper + +mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count -> + [one] pattern + *[other] patterns + } in let chain + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match + .help = consider moving {$count -> + [one] it + *[other] them + } outside of the construct + +mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> + [one] pattern + *[other] patterns + } in let chain + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match + .help = consider moving {$count -> + [one] it + *[other] them + } into the body + +mir_build_bindings_with_variant_name = + pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}` + .suggestion = to match on the variant, qualify the path + +mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the `let` is useless + .help = consider removing `let` + +mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the `if let` is useless + .help = consider replacing the `if let` with a `let` + +mir_build_irrefutable_let_patterns_if_let_guard = irrefutable `if let` guard {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the guard is useless + .help = consider removing the guard and adding a `let` inside the match arm + +mir_build_irrefutable_let_patterns_let_else = irrefutable `let...else` {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the `else` clause is useless + .help = consider removing the `else` clause + +mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the loop will never exit + .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it + +mir_build_borrow_of_moved_value = borrow of moved value + .label = value moved into `{$name}` here + .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait + .value_borrowed_label = value borrowed here after move + .suggestion = borrow this binding in the pattern to avoid moving the value + +mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time + +mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable + +mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable + +mir_build_moved_while_borrowed = cannot move out of value because it is borrowed + +mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here + +mir_build_borrow = value is borrowed by `{$name}` here + +mir_build_moved = value is moved into `{$name}` here + +mir_build_union_pattern = cannot use unions in constant patterns + +mir_build_type_not_structural = + to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` + +mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns + +mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns + +mir_build_float_pattern = floating-point types cannot be used in patterns + +mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + +mir_build_indirect_structural_match = + to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` + +mir_build_nontrivial_structural_match = + to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` + +mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints + .range = ... with this range + .note = you likely meant to write mutually exclusive ranges + +mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly + .help = ensure that all variants are matched explicitly by adding the suggested match arms + .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found + +mir_build_uncovered = {$count -> + [1] pattern `{$witness_1}` + [2] patterns `{$witness_1}` and `{$witness_2}` + [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}` + *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more + } not covered + +mir_build_pattern_not_covered = refutable pattern in {$origin} + .pattern_ty = the matched value is of type `{$pattern_ty}` + +mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + +mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + +mir_build_res_defined_here = {$res} defined here + +mir_build_adt_defined_here = `{$ty}` defined here + +mir_build_variant_defined_here = not covered + +mir_build_interpreted_as_const = introduce a variable instead + +mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable + +mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count -> + [one] variant that isn't + *[other] variants that aren't + } matched + +mir_build_suggest_let_else = you might want to use `let else` to handle the {$count -> + [one] variant that isn't + *[other] variants that aren't + } matched + +mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + + +mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly + .attributes = no other attributes may be applied + .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call + .missing_box = `#[rustc_box]` requires the `owned_box` lang item diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 0bca02589..dbba529ae 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -18,6 +18,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { @call("mir_storage_dead", args) => { Ok(StatementKind::StorageDead(self.parse_local(args[0])?)) }, + @call("mir_deinit", args) => { + Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?))) + }, @call("mir_retag", args) => { Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?))) }, @@ -141,12 +144,29 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> { parse_by_kind!(self, expr_id, _, "rvalue", @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant), + @call("mir_checked", args) => { + parse_by_kind!(self, args[0], _, "binary op", + ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp( + *op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)) + )), + ) + }, + @call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)), ExprKind::Borrow { borrow_kind, arg } => Ok( Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?) ), ExprKind::AddressOf { mutability, arg } => Ok( Rvalue::AddressOf(*mutability, self.parse_place(*arg)?) ), + ExprKind::Binary { op, lhs, rhs } => Ok( + Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))) + ), + ExprKind::Unary { op, arg } => Ok( + Rvalue::UnaryOp(*op, self.parse_operand(*arg)?) + ), + ExprKind::Repeat { value, count } => Ok( + Rvalue::Repeat(self.parse_operand(*value)?, *count) + ), _ => self.parse_operand(expr_id).map(Rvalue::Use), ) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 1d96893c7..cfacb5ea3 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -55,7 +55,7 @@ pub fn as_constant_inner<'tcx>( ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar)) } Err(LitToConstError::TypeError) => { - bug!("encountered type error in `lit_to_mir_constant") + bug!("encountered type error in `lit_to_mir_constant`") } }; @@ -132,14 +132,14 @@ pub(crate) fn lit_to_mir_constant<'tcx>( (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); - let allocation = tcx.intern_const_alloc(allocation); + let allocation = tcx.mk_const_alloc(allocation); ConstValue::Slice { data: allocation, start: 0, end: s.len() } } (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(_)) => { let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); - let allocation = tcx.intern_const_alloc(allocation); + let allocation = tcx.mk_const_alloc(allocation); ConstValue::Slice { data: allocation, start: 0, end: data.len() } } (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index c621efb3b..ff3198847 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Return the operand *tmp0 to be used as the call argument let place = Place { local: operand, - projection: tcx.intern_place_elems(&[PlaceElem::Deref]), + projection: tcx.mk_place_elems(&[PlaceElem::Deref]), }; return block.and(Operand::Move(place)); diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index e22fa6365..33200b80a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::AdtDef; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, Variance}; use rustc_span::Span; use rustc_target::abi::VariantIdx; @@ -183,7 +183,7 @@ fn to_upvars_resolved_place_builder<'tcx>( &projection, ) else { let closure_span = cx.tcx.def_span(closure_def_id); - if !enable_precise_capture(cx.tcx, closure_span) { + if !enable_precise_capture(closure_span) { bug!( "No associated capture found for {:?}[{:#?}] even though \ capture_disjoint_fields isn't enabled", @@ -263,7 +263,7 @@ impl<'tcx> PlaceBuilder<'tcx> { let resolved = self.resolve_upvar(cx); let builder = resolved.as_ref().unwrap_or(self); let PlaceBase::Local(local) = builder.base else { return None }; - let projection = cx.tcx.intern_place_elems(&builder.projection); + let projection = cx.tcx.mk_place_elems(&builder.projection); Some(Place { local, projection }) } @@ -692,7 +692,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); let fake_borrow_temp = self.local_decls.push(LocalDecl::new(fake_borrow_ty, expr_span)); - let projection = tcx.intern_place_elems(&base_place.projection[..idx]); + let projection = tcx.mk_place_elems(&base_place.projection[..idx]); self.cfg.push_assign( block, source_info, @@ -745,8 +745,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if -/// user is using Rust Edition 2021 or higher. -fn enable_precise_capture(tcx: TyCtxt<'_>, closure_span: Span) -> bool { - tcx.features().capture_disjoint_fields || closure_span.rust_2021() +/// Precise capture is enabled if user is using Rust Edition 2021 or higher. +fn enable_precise_capture(closure_span: Span) -> bool { + closure_span.rust_2021() } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c7b3eb44d..a4e48c154 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) } ExprKind::Repeat { value, count } => { - if Some(0) == count.try_eval_usize(this.tcx, this.param_env) { + if Some(0) == count.try_eval_target_usize(this.tcx, this.param_env) { this.build_zero_repeat(block, value, scope, source_info) } else { let value_operand = unpack!( @@ -439,10 +439,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // We implicitly set the discriminant to 0. See // librustc_mir/transform/deaggregator.rs for details. let movability = movability.unwrap(); - Box::new(AggregateKind::Generator(closure_id, substs, movability)) + Box::new(AggregateKind::Generator( + closure_id.to_def_id(), + substs, + movability, + )) } UpvarSubsts::Closure(substs) => { - Box::new(AggregateKind::Closure(closure_id, substs)) + Box::new(AggregateKind::Closure(closure_id.to_def_id(), substs)) } }; block.and(Rvalue::Aggregate(result, operands)) @@ -516,7 +520,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = self.source_info(span); let bool_ty = self.tcx.types.bool; if self.check_overflow && op.is_checkable() && ty.is_integral() { - let result_tup = self.tcx.intern_tup(&[ty, bool_ty]); + let result_tup = self.tcx.mk_tup(&[ty, bool_ty]); let result_value = self.temp(result_tup, span); self.cfg.push_assign( diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 0ca4e3745..3d3cf7555 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr_ty = expr.ty; let temp = { let mut local_decl = LocalDecl::new(expr_ty, expr_span); - if mutability == Mutability::Not { + if mutability.is_not() { local_decl = local_decl.immutable(); } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 38b1fa91d..dac9bf0a8 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -319,7 +319,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // See the notes for `ExprKind::Array` in `as_rvalue` and for // `ExprKind::Borrow` above. let is_union = adt_def.is_union(); - let active_field_index = if is_union { Some(fields[0].name.index()) } else { None }; + let active_field_index = is_union.then(|| fields[0].name.index()); let scope = this.local_scope(); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 0961ce11e..de2851a1a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1206,7 +1206,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrows.insert(Place { local: source.local, - projection: self.tcx.intern_place_elems(proj_base), + projection: self.tcx.mk_place_elems(proj_base), }); } } @@ -1743,12 +1743,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|matched_place_ref| { let matched_place = Place { local: matched_place_ref.local, - projection: tcx.intern_place_elems(matched_place_ref.projection), + projection: tcx.mk_place_elems(matched_place_ref.projection), }; let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); - let fake_borrow_temp = - self.local_decls.push(LocalDecl::new(fake_borrow_ty, temp_span)); + let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); + fake_borrow_temp.internal = self.local_decls[matched_place.local].internal; + fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow)); + let fake_borrow_temp = self.local_decls.push(fake_borrow_temp); (matched_place, fake_borrow_temp) }) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index ad7a568a2..2de89f67d 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -563,14 +563,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let not_contained = self.values_not_contained_in_range(&*range, options).unwrap_or(false); - if not_contained { + not_contained.then(|| { // No switch values are contained in the pattern range, // so the pattern can be matched only if this test fails. - let otherwise = options.len(); - Some(otherwise) - } else { - None - } + options.len() + }) } (&TestKind::SwitchInt { .. }, _) => None, @@ -835,7 +832,7 @@ fn trait_method<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, method_name: Symbol, - substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>, + substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, ) -> ConstantKind<'tcx> { // The unhygienic comparison here is acceptable because this is only // used on known traits. diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index cbd494862..c34105174 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -5,7 +5,7 @@ use crate::build::Builder; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty; -use rustc_middle::ty::TypeVisitable; +use rustc_middle::ty::TypeVisitableExt; use smallvec::SmallVec; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -35,7 +35,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.tcx; let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { match place_resolved.ty(&self.local_decls, tcx).ty.kind() { - ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), + ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), } } else { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 9daf68a15..b3f9d8282 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::mir::*; use rustc_middle::thir::{ self, BindingMode, Expr, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir, }; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_span::Symbol; @@ -47,8 +47,6 @@ pub(crate) fn mir_built( /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> { - let body_owner_kind = tcx.hir().body_owner_kind(def.did); - // Ensure unsafeck and abstract const building is ran before we steal the THIR. // We can't use `ensure()` for `thir_abstract_const` as it doesn't compute the query // if inputs are green. This can cause ICEs when calling `thir_abstract_const` after @@ -65,16 +63,15 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ } let body = match tcx.thir_body(def) { - Err(error_reported) => construct_error(tcx, def.did, body_owner_kind, error_reported), + Err(error_reported) => construct_error(tcx, def.did, error_reported), Ok((thir, expr)) => { // We ran all queries that depended on THIR at the beginning // of `mir_build`, so now we can steal it let thir = thir.steal(); - if body_owner_kind.is_fn_or_closure() { - construct_fn(tcx, def, &thir, expr) - } else { - construct_const(tcx, def, &thir, expr) + match thir.body_type { + thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig), + thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty), } } }; @@ -158,13 +155,13 @@ struct BlockContext(Vec<BlockFrame>); struct Builder<'a, 'tcx> { tcx: TyCtxt<'tcx>, infcx: InferCtxt<'tcx>, - typeck_results: &'tcx TypeckResults<'tcx>, region_scope_tree: &'tcx region::ScopeTree, param_env: ty::ParamEnv<'tcx>, thir: &'a Thir<'tcx>, cfg: CFG<'tcx>, + def: ty::WithOptConstParam<LocalDefId>, def_id: DefId, hir_id: hir::HirId, parent_module: DefId, @@ -434,11 +431,16 @@ fn construct_fn<'tcx>( fn_def: ty::WithOptConstParam<LocalDefId>, thir: &Thir<'tcx>, expr: ExprId, + fn_sig: ty::FnSig<'tcx>, ) -> Body<'tcx> { let span = tcx.def_span(fn_def.did); let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did); let generator_kind = tcx.generator_kind(fn_def.did); + // The representation of thir for `-Zunpretty=thir-tree` relies on + // the entry expression being the last element of `thir.exprs`. + assert_eq!(expr.as_usize(), thir.exprs.len() - 1); + // Figure out what primary body this item has. let body_id = tcx.hir().body_owned_by(fn_def.did); let span_with_body = tcx.hir().span_with_body(fn_id); @@ -449,11 +451,6 @@ fn construct_fn<'tcx>( .output .span(); - // fetch the fully liberated fn signature (that is, all bound - // types/lifetimes replaced) - let typeck_results = tcx.typeck_opt_const_arg(fn_def); - let fn_sig = typeck_results.liberated_fn_sigs()[fn_id]; - let safety = match fn_sig.unsafety { hir::Unsafety::Normal => Safety::Safe, hir::Unsafety::Unsafe => Safety::FnUnsafe, @@ -525,13 +522,7 @@ fn construct_fn<'tcx>( let return_block = unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { - builder.args_and_body( - START_BLOCK, - fn_def.did, - arguments, - arg_scope, - &thir[expr], - ) + builder.args_and_body(START_BLOCK, arguments, arg_scope, &thir[expr]) })) })); let source_info = builder.source_info(fn_end); @@ -559,6 +550,7 @@ fn construct_const<'a, 'tcx>( def: ty::WithOptConstParam<LocalDefId>, thir: &'a Thir<'tcx>, expr: ExprId, + const_ty: Ty<'tcx>, ) -> Body<'tcx> { let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); @@ -582,20 +574,6 @@ fn construct_const<'a, 'tcx>( _ => span_bug!(tcx.def_span(def.did), "can't build MIR for {:?}", def.did), }; - // Get the revealed type of this const. This is *not* the adjusted - // type of its body, which may be a subtype of this type. For - // example: - // - // fn foo(_: &()) {} - // static X: fn(&'static ()) = foo; - // - // The adjusted type of the body of X is `for<'a> fn(&'a ())` which - // is not the same as the type of X. We need the type of the return - // place to be the type of the constant because NLL typeck will - // equate them. - let typeck_results = tcx.typeck_opt_const_arg(def); - let const_ty = typeck_results.node_type(hir_id); - let infcx = tcx.infer_ctxt().build(); let mut builder = Builder::new( thir, @@ -625,21 +603,17 @@ fn construct_const<'a, 'tcx>( /// /// This is required because we may still want to run MIR passes on an item /// with type errors, but normal MIR construction can't handle that in general. -fn construct_error( - tcx: TyCtxt<'_>, - def: LocalDefId, - body_owner_kind: hir::BodyOwnerKind, - err: ErrorGuaranteed, -) -> Body<'_> { +fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Body<'_> { let span = tcx.def_span(def); let hir_id = tcx.hir().local_def_id_to_hir_id(def); let generator_kind = tcx.generator_kind(def); + let body_owner_kind = tcx.hir().body_owner_kind(def); - let ty = tcx.ty_error(); + let ty = tcx.ty_error(err); let num_params = match body_owner_kind { - hir::BodyOwnerKind::Fn => tcx.fn_sig(def).inputs().skip_binder().len(), + hir::BodyOwnerKind::Fn => tcx.fn_sig(def).skip_binder().inputs().skip_binder().len(), hir::BodyOwnerKind::Closure => { - let ty = tcx.type_of(def); + let ty = tcx.type_of(def).subst_identity(); match ty.kind() { ty::Closure(_, substs) => { 1 + substs.as_closure().sig().inputs().skip_binder().len() @@ -724,9 +698,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { thir, tcx, infcx, - typeck_results: tcx.typeck_opt_const_arg(def), region_scope_tree: tcx.region_scope_tree(def.did), param_env, + def, def_id: def.did.to_def_id(), hir_id, parent_module: tcx.parent_module(hir_id).to_def_id(), @@ -776,14 +750,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info, self.fn_span, self.generator_kind, - self.typeck_results.tainted_by_errors, + None, ) } + fn insert_upvar_arg(&mut self) { + let Some(closure_arg) = self.local_decls.get(ty::CAPTURE_STRUCT_LOCAL) else { return }; + + let mut closure_ty = closure_arg.ty; + let mut closure_env_projs = vec![]; + if let ty::Ref(_, ty, _) = closure_ty.kind() { + closure_env_projs.push(ProjectionElem::Deref); + closure_ty = *ty; + } + + let upvar_substs = match closure_ty.kind() { + ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), + ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), + _ => return, + }; + + // In analyze_closure() in upvar.rs we gathered a list of upvars used by an + // indexed closure and we stored in a map called closure_min_captures in TypeckResults + // with the closure's DefId. Here, we run through that vec of UpvarIds for + // the given closure and use the necessary information to create upvar + // debuginfo and to fill `self.upvars`. + let capture_tys = upvar_substs.upvar_tys(); + + let tcx = self.tcx; + self.upvars = tcx + .closure_captures(self.def.did) + .iter() + .zip(capture_tys) + .enumerate() + .map(|(i, (captured_place, ty))| { + let name = captured_place.to_symbol(); + + let capture = captured_place.info.capture_kind; + let var_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + _ => bug!("Expected an upvar"), + }; + + let mutability = captured_place.mutability; + + let mut projs = closure_env_projs.clone(); + projs.push(ProjectionElem::Field(Field::new(i), ty)); + match capture { + ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByRef(..) => { + projs.push(ProjectionElem::Deref); + } + }; + + let use_place = Place { + local: ty::CAPTURE_STRUCT_LOCAL, + projection: tcx.mk_place_elems(&projs), + }; + self.var_debug_info.push(VarDebugInfo { + name, + source_info: SourceInfo::outermost(captured_place.var_ident.span), + value: VarDebugInfoContents::Place(use_place), + }); + + let capture = Capture { captured_place, use_place, mutability }; + (var_id, capture) + }) + .collect(); + } + fn args_and_body( &mut self, mut block: BasicBlock, - fn_def_id: LocalDefId, arguments: &IndexVec<ParamId, Param<'tcx>>, argument_scope: region::Scope, expr: &Expr<'tcx>, @@ -805,69 +843,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let tcx = self.tcx; - let tcx_hir = tcx.hir(); - let hir_typeck_results = self.typeck_results; - - // In analyze_closure() in upvar.rs we gathered a list of upvars used by an - // indexed closure and we stored in a map called closure_min_captures in TypeckResults - // with the closure's DefId. Here, we run through that vec of UpvarIds for - // the given closure and use the necessary information to create upvar - // debuginfo and to fill `self.upvars`. - if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() { - let mut closure_env_projs = vec![]; - let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; - if let ty::Ref(_, ty, _) = closure_ty.kind() { - closure_env_projs.push(ProjectionElem::Deref); - closure_ty = *ty; - } - let upvar_substs = match closure_ty.kind() { - ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), - ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), - _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty), - }; - let def_id = self.def_id.as_local().unwrap(); - let capture_syms = tcx.symbols_for_closure_captures((def_id, fn_def_id)); - let capture_tys = upvar_substs.upvar_tys(); - let captures_with_tys = hir_typeck_results - .closure_min_captures_flattened(fn_def_id) - .zip(capture_tys.zip(capture_syms)); - - self.upvars = captures_with_tys - .enumerate() - .map(|(i, (captured_place, (ty, sym)))| { - let capture = captured_place.info.capture_kind; - let var_id = match captured_place.place.base { - HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, - _ => bug!("Expected an upvar"), - }; - - let mutability = captured_place.mutability; - - let mut projs = closure_env_projs.clone(); - projs.push(ProjectionElem::Field(Field::new(i), ty)); - match capture { - ty::UpvarCapture::ByValue => {} - ty::UpvarCapture::ByRef(..) => { - projs.push(ProjectionElem::Deref); - } - }; - - let use_place = Place { - local: ty::CAPTURE_STRUCT_LOCAL, - projection: tcx.intern_place_elems(&projs), - }; - self.var_debug_info.push(VarDebugInfo { - name: *sym, - source_info: SourceInfo::outermost(tcx_hir.span(var_id)), - value: VarDebugInfoContents::Place(use_place), - }); - - let capture = Capture { captured_place, use_place, mutability }; - (var_id, capture) - }) - .collect(); - } + self.insert_upvar_arg(); let mut scope = None; // Bind the argument patterns diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 7f81aef1c..dc4d2276e 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,9 +1,10 @@ -use crate::thir::pattern::deconstruct_pat::DeconstructedPat; -use crate::thir::pattern::MatchCheckCtxt; -use rustc_errors::Handler; +use crate::{ + fluent_generated as fluent, + thir::pattern::{deconstruct_pat::DeconstructedPat, MatchCheckCtxt}, +}; use rustc_errors::{ error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - IntoDiagnostic, MultiSpan, SubdiagnosticMessage, + Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage, }; use rustc_hir::def::Res; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -358,7 +359,7 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { let mut diag = handler.struct_span_err_with_code( self.span, - rustc_errors::fluent::mir_build_non_exhaustive_patterns_type_not_empty, + fluent::mir_build_non_exhaustive_patterns_type_not_empty, error_code!(E0004), ); @@ -380,7 +381,7 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { let mut span: MultiSpan = def_span.into(); span.push_span_label(def_span, ""); - diag.span_note(span, rustc_errors::fluent::def_note); + diag.span_note(span, fluent::mir_build_def_note); } let is_variant_list_non_exhaustive = match self.ty.kind() { @@ -391,14 +392,14 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { }; if is_variant_list_non_exhaustive { - diag.note(rustc_errors::fluent::non_exhaustive_type_note); + diag.note(fluent::mir_build_non_exhaustive_type_note); } else { - diag.note(rustc_errors::fluent::type_note); + diag.note(fluent::mir_build_type_note); } if let ty::Ref(_, sub_ty, _) = self.ty.kind() { if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.param_env) { - diag.note(rustc_errors::fluent::reference_note); + diag.note(fluent::mir_build_reference_note); } } @@ -424,12 +425,12 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { if let Some((span, sugg)) = suggestion { diag.span_suggestion_verbose( span, - rustc_errors::fluent::suggestion, + fluent::mir_build_suggestion, sugg, Applicability::HasPlaceholders, ); } else { - diag.help(rustc_errors::fluent::help); + diag.help(fluent::mir_build_help); } diag @@ -469,7 +470,7 @@ pub struct NonConstPath { pub struct UnreachablePattern { #[label] pub span: Option<Span>, - #[label(catchall_label)] + #[label(mir_build_catchall_label)] pub catchall: Option<Span>, } @@ -493,7 +494,7 @@ pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper { #[primary_span] #[label] pub span: Span, - #[note(teach_note)] + #[note(mir_build_teach_note)] pub teach: Option<()>, } @@ -585,9 +586,9 @@ pub struct BorrowOfMovedValue<'tcx> { #[primary_span] pub span: Span, #[label] - #[label(occurs_because_label)] + #[label(mir_build_occurs_because_label)] pub binding_span: Span, - #[label(value_borrowed_label)] + #[label(mir_build_value_borrowed_label)] pub conflicts_ref: Vec<Span>, pub name: Ident, pub ty: Ty<'tcx>, @@ -600,32 +601,56 @@ pub struct BorrowOfMovedValue<'tcx> { pub struct MultipleMutBorrows { #[primary_span] pub span: Span, - #[label] - pub binding_span: Span, #[subdiagnostic] - pub occurences: Vec<MultipleMutBorrowOccurence>, - pub name: Ident, + pub occurences: Vec<Conflict>, +} + +#[derive(Diagnostic)] +#[diag(mir_build_already_borrowed)] +pub struct AlreadyBorrowed { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub occurences: Vec<Conflict>, +} + +#[derive(Diagnostic)] +#[diag(mir_build_already_mut_borrowed)] +pub struct AlreadyMutBorrowed { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub occurences: Vec<Conflict>, +} + +#[derive(Diagnostic)] +#[diag(mir_build_moved_while_borrowed)] +pub struct MovedWhileBorrowed { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub occurences: Vec<Conflict>, } #[derive(Subdiagnostic)] -pub enum MultipleMutBorrowOccurence { - #[label(mutable_borrow)] - Mutable { +pub enum Conflict { + #[label(mir_build_mutable_borrow)] + Mut { #[primary_span] span: Span, - name_mut: Ident, + name: Ident, }, - #[label(immutable_borrow)] - Immutable { + #[label(mir_build_borrow)] + Ref { #[primary_span] span: Span, - name_immut: Ident, + name: Ident, }, - #[label(moved)] + #[label(mir_build_moved)] Moved { #[primary_span] span: Span, - name_moved: Ident, + name: Ident, }, } @@ -684,7 +709,7 @@ pub struct NontrivialStructuralMatch<'tcx> { #[diag(mir_build_overlapping_range_endpoints)] #[note] pub struct OverlappingRangeEndpoints<'tcx> { - #[label(range)] + #[label(mir_build_range)] pub range: Span, #[subdiagnostic] pub overlap: Vec<Overlap<'tcx>>, @@ -764,7 +789,7 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub interpreted_as_const: Option<InterpretedAsConst>, #[subdiagnostic] pub adt_defined_here: Option<AdtDefinedHere<'tcx>>, - #[note(pattern_ty)] + #[note(mir_build_pattern_ty)] pub _p: (), pub pattern_ty: Ty<'tcx>, #[subdiagnostic] @@ -799,10 +824,10 @@ impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> { let mut spans = MultiSpan::from(self.adt_def_span); for Variant { span } in self.variants { - spans.push_span_label(span, rustc_errors::fluent::mir_build_variant_defined_here); + spans.push_span_label(span, fluent::mir_build_variant_defined_here); } - diag.span_note(spans, rustc_errors::fluent::mir_build_adt_defined_here); + diag.span_note(spans, fluent::mir_build_adt_defined_here); } } @@ -863,3 +888,22 @@ pub enum MiscPatternSuggestion { start_span: Span, }, } + +#[derive(Diagnostic)] +#[diag(mir_build_rustc_box_attribute_error)] +pub struct RustcBoxAttributeError { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub reason: RustcBoxAttrReason, +} + +#[derive(Subdiagnostic)] +pub enum RustcBoxAttrReason { + #[note(mir_build_attributes)] + Attributes, + #[note(mir_build_not_box)] + NotBoxNew, + #[note(mir_build_missing_box)] + MissingBox, +} diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index a428180a4..e10a264d3 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -25,6 +25,11 @@ pub mod thir; use rustc_middle::ty::query::Providers; +use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_macros::fluent_messages; + +fluent_messages! { "../locales/en-US.ftl" } + pub fn provide(providers: &mut Providers) { providers.check_match = thir::pattern::check_match; providers.lit_to_const = thir::constant::lit_to_const; @@ -33,5 +38,6 @@ pub fn provide(providers: &mut Providers) { providers.thir_check_unsafety = check_unsafety::thir_check_unsafety; providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg; providers.thir_body = thir::cx::thir_body; - providers.thir_tree = thir::cx::thir_tree; + providers.thir_tree = thir::print::thir_tree; + providers.thir_flat = thir::print::thir_flat; } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 261b95ba9..9086412c0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,3 +1,4 @@ +use crate::errors; use crate::thir::cx::region::Scope; use crate::thir::cx::Cx; use crate::thir::util::UserAnnotatedTyHelpers; @@ -18,7 +19,7 @@ use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{ self, AdtKind, InlineConstSubsts, InlineConstSubstsParts, ScalarInt, Ty, UpvarSubsts, UserType, }; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::abi::VariantIdx; impl<'tcx> Cx<'tcx> { @@ -33,8 +34,6 @@ impl<'tcx> Cx<'tcx> { #[instrument(level = "trace", skip(self, hir_expr))] pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId { - let temp_lifetime = - self.rvalue_scopes.temporary_scope(self.region_scope_tree, hir_expr.hir_id.local_id); let expr_scope = region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node }; @@ -67,7 +66,7 @@ impl<'tcx> Cx<'tcx> { // Next, wrap this up in the expr's scope. expr = Expr { - temp_lifetime, + temp_lifetime: expr.temp_lifetime, ty: expr.ty, span: hir_expr.span, kind: ExprKind::Scope { @@ -82,7 +81,7 @@ impl<'tcx> Cx<'tcx> { self.region_scope_tree.opt_destruction_scope(hir_expr.hir_id.local_id) { expr = Expr { - temp_lifetime, + temp_lifetime: expr.temp_lifetime, ty: expr.ty, span: hir_expr.span, kind: ExprKind::Scope { @@ -262,6 +261,7 @@ impl<'tcx> Cx<'tcx> { } } + #[instrument(level = "debug", skip(self), ret)] fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { let tcx = self.tcx; let expr_ty = self.typeck_results().expr_ty(expr); @@ -307,7 +307,7 @@ impl<'tcx> Cx<'tcx> { let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e)); let tupled_args = Expr { - ty: tcx.mk_tup(arg_tys), + ty: tcx.mk_tup_from_iter(arg_tys), temp_lifetime, span: expr.span, kind: ExprKind::Tuple { fields: self.mirror_exprs(args) }, @@ -322,6 +322,34 @@ impl<'tcx> Cx<'tcx> { fn_span: expr.span, } } else { + let attrs = tcx.hir().attrs(expr.hir_id); + if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_box) { + if attrs.len() != 1 { + tcx.sess.emit_err(errors::RustcBoxAttributeError { + span: attrs[0].span, + reason: errors::RustcBoxAttrReason::Attributes, + }); + } else if let Some(box_item) = tcx.lang_items().owned_box() { + if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) = fun.kind + && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind + && path.res.opt_def_id().map_or(false, |did| did == box_item) + && fn_path.ident.name == sym::new + && let [value] = args + { + return Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind: ExprKind::Box { value: self.mirror_expr(value) } } + } else { + tcx.sess.emit_err(errors::RustcBoxAttributeError { + span: expr.span, + reason: errors::RustcBoxAttrReason::NotBoxNew + }); + } + } else { + tcx.sess.emit_err(errors::RustcBoxAttributeError { + span: attrs[0].span, + reason: errors::RustcBoxAttrReason::MissingBox, + }); + } + } let adt_data = if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind { // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. @@ -541,8 +569,9 @@ impl<'tcx> Cx<'tcx> { let def_id = def_id.expect_local(); let upvars = self - .typeck_results - .closure_min_captures_flattened(def_id) + .tcx + .closure_captures(def_id) + .iter() .zip(substs.upvar_tys()) .map(|(captured_place, ty)| { let upvars = self.capture_upvar(expr, captured_place, ty); @@ -758,7 +787,7 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) }, hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: self.mirror_expr(v) }, - hir::ExprKind::Err => unreachable!(), + hir::ExprKind::Err(_) => unreachable!(), }; Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index a355e1bda..070544446 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -52,13 +52,6 @@ pub(crate) fn thir_body( Ok((tcx.alloc_steal_thir(cx.thir), expr)) } -pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String { - match thir_body(tcx, owner_def) { - Ok((thir, _)) => format!("{:#?}", thir.steal()), - Err(_) => "error".into(), - } -} - struct Cx<'tcx> { tcx: TyCtxt<'tcx>, thir: Thir<'tcx>, @@ -89,9 +82,30 @@ impl<'tcx> Cx<'tcx> { let typeck_results = tcx.typeck_opt_const_arg(def); let did = def.did; let hir = tcx.hir(); + let hir_id = hir.local_def_id_to_hir_id(did); + + let body_type = if hir.body_owner_kind(did).is_fn_or_closure() { + // fetch the fully liberated fn signature (that is, all bound + // types/lifetimes replaced) + BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id]) + } else { + // Get the revealed type of this const. This is *not* the adjusted + // type of its body, which may be a subtype of this type. For + // example: + // + // fn foo(_: &()) {} + // static X: fn(&'static ()) = foo; + // + // The adjusted type of the body of X is `for<'a> fn(&'a ())` which + // is not the same as the type of X. We need the type of the return + // place to be the type of the constant because NLL typeck will + // equate them. + BodyTy::Const(typeck_results.node_type(hir_id)) + }; + Cx { tcx, - thir: Thir::new(), + thir: Thir::new(body_type), param_env: tcx.param_env(def.did), region_scope_tree: tcx.region_scope_tree(def.did), typeck_results, @@ -99,7 +113,7 @@ impl<'tcx> Cx<'tcx> { body_owner: did.to_def_id(), adjustment_span: None, apply_adjustments: hir - .attrs(hir.local_def_id_to_hir_id(did)) + .attrs(hir_id) .iter() .all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir), } @@ -123,14 +137,13 @@ impl<'tcx> Cx<'tcx> { bug!("closure expr does not have closure type: {:?}", closure_ty); }; - let bound_vars = self.tcx.mk_bound_variable_kinds(std::iter::once( - ty::BoundVariableKind::Region(ty::BrEnv), - )); + let bound_vars = + self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region(ty::BrEnv)]); let br = ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BrEnv, }; - let env_region = ty::ReLateBound(ty::INNERMOST, br); + let env_region = self.tcx.mk_re_late_bound(ty::INNERMOST, br); let closure_env_ty = self.tcx.closure_env_ty(closure_def_id, closure_substs, env_region).unwrap(); let liberated_closure_env_ty = self.tcx.erase_late_bound_regions( @@ -183,7 +196,7 @@ impl<'tcx> Cx<'tcx> { let va_list_did = self.tcx.require_lang_item(LangItem::VaList, Some(param.span)); self.tcx - .bound_type_of(va_list_did) + .type_of(va_list_did) .subst(self.tcx, &[self.tcx.lifetimes.re_erased.into()]) } else { fn_sig.inputs()[index] diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index e0e6ac266..ca26cc13b 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -5,9 +5,7 @@ //! structures. pub(crate) mod constant; - pub(crate) mod cx; - pub(crate) mod pattern; - +pub(crate) mod print; mod util; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 34e637f59..2640ca56b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -208,9 +208,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` // when the iterator is an uninhabited type. unreachable_code will trigger instead. hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {} - hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - report_arm_reachability(&cx, &report) - } + hir::MatchSource::ForLoopDesugar + | hir::MatchSource::Normal + | hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report), // Unreachable patterns in try and await expressions occur when one of // the arms are an uninhabited type. Which is OK. hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} @@ -926,58 +926,55 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa sub.each_binding(|_, hir_id, span, name| { match typeck_results.extract_binding_mode(sess, hir_id, span) { Some(ty::BindByReference(mut_inner)) => match (mut_outer, mut_inner) { - (Mutability::Not, Mutability::Not) => {} // Both sides are `ref`. - (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`. - _ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction. + // Both sides are `ref`. + (Mutability::Not, Mutability::Not) => {} + // 2x `ref mut`. + (Mutability::Mut, Mutability::Mut) => { + conflicts_mut_mut.push(Conflict::Mut { span, name }) + } + (Mutability::Not, Mutability::Mut) => { + conflicts_mut_ref.push(Conflict::Mut { span, name }) + } + (Mutability::Mut, Mutability::Not) => { + conflicts_mut_ref.push(Conflict::Ref { span, name }) + } }, Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => { - conflicts_move.push((span, name)) // `ref mut?` + by-move conflict. + conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict. } Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine. } }); + let report_mut_mut = !conflicts_mut_mut.is_empty(); + let report_mut_ref = !conflicts_mut_ref.is_empty(); + let report_move_conflict = !conflicts_move.is_empty(); + + let mut occurences = match mut_outer { + Mutability::Mut => vec![Conflict::Mut { span: binding_span, name }], + Mutability::Not => vec![Conflict::Ref { span: binding_span, name }], + }; + occurences.extend(conflicts_mut_mut); + occurences.extend(conflicts_mut_ref); + occurences.extend(conflicts_move); + // Report errors if any. - if !conflicts_mut_mut.is_empty() { + if report_mut_mut { // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. - let mut occurences = vec![]; - - for (span, name_mut) in conflicts_mut_mut { - occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut }); - } - for (span, name_immut) in conflicts_mut_ref { - occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut }); - } - for (span, name_moved) in conflicts_move { - occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved }); - } - sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name }); - } else if !conflicts_mut_ref.is_empty() { + sess.emit_err(MultipleMutBorrows { span: pat.span, occurences }); + } else if report_mut_ref { // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. - let (primary, also) = match mut_outer { - Mutability::Mut => ("mutable", "immutable"), - Mutability::Not => ("immutable", "mutable"), + match mut_outer { + Mutability::Mut => { + sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurences }); + } + Mutability::Not => { + sess.emit_err(AlreadyBorrowed { span: pat.span, occurences }); + } }; - let msg = - format!("cannot borrow value as {} because it is also borrowed as {}", also, primary); - let mut err = sess.struct_span_err(pat.span, &msg); - err.span_label(binding_span, format!("{} borrow, by `{}`, occurs here", primary, name)); - for (span, name) in conflicts_mut_ref { - err.span_label(span, format!("{} borrow, by `{}`, occurs here", also, name)); - } - for (span, name) in conflicts_move { - err.span_label(span, format!("also moved into `{}` here", name)); - } - err.emit(); - } else if !conflicts_move.is_empty() { + } else if report_move_conflict { // Report by-ref and by-move conflicts, e.g. `ref x @ y`. - let mut err = - sess.struct_span_err(pat.span, "cannot move out of value because it is borrowed"); - err.span_label(binding_span, format!("value borrowed, by `{}`, here", name)); - for (span, name) in conflicts_move { - err.span_label(span, format!("value moved into `{}` here", name)); - } - err.emit(); + sess.emit_err(MovedWhileBorrowed { span: pat.span, occurences }); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 7f3519945..ff88d0013 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -192,7 +192,7 @@ impl<'tcx> ConstToPat<'tcx> { let obligation: PredicateObligation<'_> = predicate_for_trait_def( self.tcx(), self.param_env, - ObligationCause::misc(self.span, self.id), + ObligationCause::misc(self.span, self.id.owner.def_id), partial_eq_trait_id, 0, [ty, ty], diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index aba5429da..e5b7d685c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -172,7 +172,7 @@ impl IntRange { ty: Ty<'tcx>, end: &RangeEnd, ) -> Option<IntRange> { - if Self::is_integral(ty) { + Self::is_integral(ty).then(|| { // Perform a shift if the underlying types are signed, // which makes the interval arithmetic simpler. let bias = IntRange::signed_bias(tcx, ty); @@ -182,10 +182,8 @@ impl IntRange { // This should have been caught earlier by E0030. bug!("malformed range pattern: {}..={}", lo, (hi - offset)); } - Some(IntRange { range: lo..=(hi - offset), bias }) - } else { - None - } + IntRange { range: lo..=(hi - offset), bias } + }) } // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it. @@ -922,8 +920,8 @@ impl<'tcx> SplitWildcard<'tcx> { // `cx.is_uninhabited()`). let all_ctors = match pcx.ty.kind() { ty::Bool => smallvec![make_range(0, 1)], - ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { - let len = len.eval_usize(cx.tcx, cx.param_env) as usize; + ty::Array(sub_ty, len) if len.try_eval_target_usize(cx.tcx, cx.param_env).is_some() => { + let len = len.eval_target_usize(cx.tcx, cx.param_env) as usize; if len != 0 && cx.is_uninhabited(*sub_ty) { smallvec![] } else { @@ -1406,7 +1404,9 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { let array_len = match pat.ty.kind() { - ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env) as usize), + ty::Array(_, length) => { + Some(length.eval_target_usize(cx.tcx, cx.param_env) as usize) + } ty::Slice(_) => None, _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3a6ef87c9..41306dd80 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -203,11 +203,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if !lower_overflow && !higher_overflow { self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { span, - teach: if self.tcx.sess.teach(&error_code!(E0030)) { - Some(()) - } else { - None - }, + teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()), }); } PatKind::Wild @@ -416,7 +412,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty::Slice(..) => PatKind::Slice { prefix, slice, suffix }, // Fixed-length array, `[T; len]`. ty::Array(_, len) => { - let len = len.eval_usize(self.tcx, self.param_env); + let len = len.eval_target_usize(self.tcx, self.param_env); assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatKind::Array { prefix, slice, suffix } } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs new file mode 100644 index 000000000..8028227aa --- /dev/null +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -0,0 +1,892 @@ +use rustc_middle::thir::*; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::LocalDefId; +use std::fmt::{self, Write}; + +pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String { + match super::cx::thir_body(tcx, owner_def) { + Ok((thir, _)) => { + let thir = thir.steal(); + let mut printer = ThirPrinter::new(&thir); + printer.print(); + printer.into_buffer() + } + Err(_) => "error".into(), + } +} + +pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String { + match super::cx::thir_body(tcx, owner_def) { + Ok((thir, _)) => format!("{:#?}", thir.steal()), + Err(_) => "error".into(), + } +} + +struct ThirPrinter<'a, 'tcx> { + thir: &'a Thir<'tcx>, + fmt: String, +} + +const INDENT: &str = " "; + +macro_rules! print_indented { + ($writer:ident, $s:expr, $indent_lvl:expr) => { + let indent = (0..$indent_lvl).map(|_| INDENT).collect::<Vec<_>>().concat(); + writeln!($writer, "{}{}", indent, $s).expect("unable to write to ThirPrinter"); + }; +} + +impl<'a, 'tcx> Write for ThirPrinter<'a, 'tcx> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.fmt.push_str(s); + Ok(()) + } +} + +impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { + fn new(thir: &'a Thir<'tcx>) -> Self { + Self { thir, fmt: String::new() } + } + + fn print(&mut self) { + print_indented!(self, "params: [", 0); + for param in self.thir.params.iter() { + self.print_param(param, 1); + } + print_indented!(self, "]", 0); + + print_indented!(self, "body:", 0); + let expr = ExprId::from_usize(self.thir.exprs.len() - 1); + self.print_expr(expr, 1); + } + + fn into_buffer(self) -> String { + self.fmt + } + + fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) { + let Param { pat, ty, ty_span, self_kind, hir_id } = param; + + print_indented!(self, "Param {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("ty_span: {:?}", ty_span), depth_lvl + 1); + print_indented!(self, format!("self_kind: {:?}", self_kind), depth_lvl + 1); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 1); + + if let Some(pat) = pat { + print_indented!(self, "param: Some( ", depth_lvl + 1); + self.print_pat(pat, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "param: None", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_block(&mut self, block_id: BlockId, depth_lvl: usize) { + let Block { + targeted_by_break, + opt_destruction_scope, + span, + region_scope, + stmts, + expr, + safety_mode, + } = &self.thir.blocks[block_id]; + + print_indented!(self, "Block {", depth_lvl); + print_indented!(self, format!("targeted_by_break: {}", targeted_by_break), depth_lvl + 1); + print_indented!( + self, + format!("opt_destruction_scope: {:?}", opt_destruction_scope), + depth_lvl + 1 + ); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); + print_indented!(self, format!("safety_mode: {:?}", safety_mode), depth_lvl + 1); + + if stmts.len() > 0 { + print_indented!(self, "stmts: [", depth_lvl + 1); + for stmt in stmts.iter() { + self.print_stmt(*stmt, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "stmts: []", depth_lvl + 1); + } + + if let Some(expr_id) = expr { + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + } else { + print_indented!(self, "expr: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_stmt(&mut self, stmt_id: StmtId, depth_lvl: usize) { + let Stmt { kind, opt_destruction_scope } = &self.thir.stmts[stmt_id]; + + print_indented!(self, "Stmt {", depth_lvl); + print_indented!( + self, + format!("opt_destruction_scope: {:?}", opt_destruction_scope), + depth_lvl + 1 + ); + + match kind { + StmtKind::Expr { scope, expr } => { + print_indented!(self, "kind: Expr {", depth_lvl + 1); + print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 2); + print_indented!(self, "expr:", depth_lvl + 2); + self.print_expr(*expr, depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 1); + } + StmtKind::Let { + remainder_scope, + init_scope, + pattern, + initializer, + else_block, + lint_level, + } => { + print_indented!(self, "kind: Let {", depth_lvl + 1); + print_indented!( + self, + format!("remainder_scope: {:?}", remainder_scope), + depth_lvl + 2 + ); + print_indented!(self, format!("init_scope: {:?}", init_scope), depth_lvl + 2); + + print_indented!(self, "pattern: ", depth_lvl + 2); + self.print_pat(pattern, depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + + if let Some(init) = initializer { + print_indented!(self, "initializer: Some(", depth_lvl + 2); + self.print_expr(*init, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "initializer: None", depth_lvl + 2); + } + + if let Some(else_block) = else_block { + print_indented!(self, "else_block: Some(", depth_lvl + 2); + self.print_block(*else_block, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "else_block: None", depth_lvl + 2); + } + + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_expr(&mut self, expr: ExprId, depth_lvl: usize) { + let Expr { ty, temp_lifetime, span, kind } = &self.thir[expr]; + print_indented!(self, "Expr {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("temp_lifetime: {:?}", temp_lifetime), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "kind: ", depth_lvl + 1); + self.print_expr_kind(kind, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + + fn print_expr_kind(&mut self, expr_kind: &ExprKind<'tcx>, depth_lvl: usize) { + use rustc_middle::thir::ExprKind::*; + + match expr_kind { + Scope { region_scope, value, lint_level } => { + print_indented!(self, "Scope {", depth_lvl); + print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Box { value } => { + print_indented!(self, "Box {", depth_lvl); + self.print_expr(*value, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + If { if_then_scope, cond, then, else_opt } => { + print_indented!(self, "If {", depth_lvl); + print_indented!(self, format!("if_then_scope: {:?}", if_then_scope), depth_lvl + 1); + print_indented!(self, "cond:", depth_lvl + 1); + self.print_expr(*cond, depth_lvl + 2); + print_indented!(self, "then:", depth_lvl + 1); + self.print_expr(*then, depth_lvl + 2); + + if let Some(else_expr) = else_opt { + print_indented!(self, "else:", depth_lvl + 1); + self.print_expr(*else_expr, depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl); + } + Call { fun, args, ty, from_hir_call, fn_span } => { + print_indented!(self, "Call {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("from_hir_call: {}", from_hir_call), depth_lvl + 1); + print_indented!(self, format!("fn_span: {:?}", fn_span), depth_lvl + 1); + print_indented!(self, "fun:", depth_lvl + 1); + self.print_expr(*fun, depth_lvl + 2); + + if args.len() > 0 { + print_indented!(self, "args: [", depth_lvl + 1); + for arg in args.iter() { + self.print_expr(*arg, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "args: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + Deref { arg } => { + print_indented!(self, "Deref {", depth_lvl); + self.print_expr(*arg, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Binary { op, lhs, rhs } => { + print_indented!(self, "Binary {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + LogicalOp { op, lhs, rhs } => { + print_indented!(self, "LogicalOp {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Unary { op, arg } => { + print_indented!(self, "Unary {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Cast { source } => { + print_indented!(self, "Cast {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Use { source } => { + print_indented!(self, "Use {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + NeverToAny { source } => { + print_indented!(self, "NeverToAny {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Pointer { cast, source } => { + print_indented!(self, "Pointer {", depth_lvl); + print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Loop { body } => { + print_indented!(self, "Loop (", depth_lvl); + print_indented!(self, "body:", depth_lvl + 1); + self.print_expr(*body, depth_lvl + 2); + print_indented!(self, ")", depth_lvl); + } + Let { expr, pat } => { + print_indented!(self, "Let {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, format!("pat: {:?}", pat), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Match { scrutinee, arms } => { + print_indented!(self, "Match {", depth_lvl); + print_indented!(self, "scrutinee:", depth_lvl + 1); + self.print_expr(*scrutinee, depth_lvl + 2); + + print_indented!(self, "arms: [", depth_lvl + 1); + for arm_id in arms.iter() { + self.print_arm(*arm_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Block { block } => self.print_block(*block, depth_lvl), + Assign { lhs, rhs } => { + print_indented!(self, "Assign {", depth_lvl); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + AssignOp { op, lhs, rhs } => { + print_indented!(self, "AssignOp {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Field { lhs, variant_index, name } => { + print_indented!(self, "Field {", depth_lvl); + print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 1); + print_indented!(self, format!("name: {:?}", name), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Index { lhs, index } => { + print_indented!(self, "Index {", depth_lvl); + print_indented!(self, format!("index: {:?}", index), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + VarRef { id } => { + print_indented!(self, "VarRef {", depth_lvl); + print_indented!(self, format!("id: {:?}", id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + UpvarRef { closure_def_id, var_hir_id } => { + print_indented!(self, "UpvarRef {", depth_lvl); + print_indented!( + self, + format!("closure_def_id: {:?}", closure_def_id), + depth_lvl + 1 + ); + print_indented!(self, format!("var_hir_id: {:?}", var_hir_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Borrow { borrow_kind, arg } => { + print_indented!(self, "Borrow (", depth_lvl); + print_indented!(self, format!("borrow_kind: {:?}", borrow_kind), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, ")", depth_lvl); + } + AddressOf { mutability, arg } => { + print_indented!(self, "AddressOf {", depth_lvl); + print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Break { label, value } => { + print_indented!(self, "Break (", depth_lvl); + print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); + + if let Some(value) = value { + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + } + + print_indented!(self, ")", depth_lvl); + } + Continue { label } => { + print_indented!(self, "Continue {", depth_lvl); + print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Return { value } => { + print_indented!(self, "Return {", depth_lvl); + print_indented!(self, "value:", depth_lvl + 1); + + if let Some(value) = value { + self.print_expr(*value, depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl); + } + ConstBlock { did, substs } => { + print_indented!(self, "ConstBlock {", depth_lvl); + print_indented!(self, format!("did: {:?}", did), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Repeat { value, count } => { + print_indented!(self, "Repeat {", depth_lvl); + print_indented!(self, format!("count: {:?}", count), depth_lvl + 1); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Array { fields } => { + print_indented!(self, "Array {", depth_lvl); + print_indented!(self, "fields: [", depth_lvl + 1); + for field_id in fields.iter() { + self.print_expr(*field_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Tuple { fields } => { + print_indented!(self, "Tuple {", depth_lvl); + print_indented!(self, "fields: [", depth_lvl + 1); + for field_id in fields.iter() { + self.print_expr(*field_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Adt(adt_expr) => { + print_indented!(self, "Adt {", depth_lvl); + self.print_adt_expr(&**adt_expr, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + PlaceTypeAscription { source, user_ty } => { + print_indented!(self, "PlaceTypeAscription {", depth_lvl); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + ValueTypeAscription { source, user_ty } => { + print_indented!(self, "ValueTypeAscription {", depth_lvl); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Closure(closure_expr) => { + print_indented!(self, "Closure {", depth_lvl); + print_indented!(self, "closure_expr:", depth_lvl + 1); + self.print_closure_expr(&**closure_expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Literal { lit, neg } => { + print_indented!( + self, + format!("Literal( lit: {:?}, neg: {:?})\n", lit, neg), + depth_lvl + ); + } + NonHirLiteral { lit, user_ty } => { + print_indented!(self, "NonHirLiteral {", depth_lvl); + print_indented!(self, format!("lit: {:?}", lit), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + ZstLiteral { user_ty } => { + print_indented!(self, format!("ZstLiteral(user_ty: {:?})", user_ty), depth_lvl); + } + NamedConst { def_id, substs, user_ty } => { + print_indented!(self, "NamedConst {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + ConstParam { param, def_id } => { + print_indented!(self, "ConstParam {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("param: {:?}", param), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + StaticRef { alloc_id, ty, def_id } => { + print_indented!(self, "StaticRef {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("alloc_id: {:?}", alloc_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + InlineAsm(expr) => { + print_indented!(self, "InlineAsm {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_inline_asm_expr(&**expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + ThreadLocalRef(def_id) => { + print_indented!(self, "ThreadLocalRef {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Yield { value } => { + print_indented!(self, "Yield {", depth_lvl); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + } + } + + fn print_adt_expr(&mut self, adt_expr: &AdtExpr<'tcx>, depth_lvl: usize) { + print_indented!(self, "adt_def:", depth_lvl); + self.print_adt_def(adt_expr.adt_def, depth_lvl + 1); + print_indented!( + self, + format!("variant_index: {:?}", adt_expr.variant_index), + depth_lvl + 1 + ); + print_indented!(self, format!("substs: {:?}", adt_expr.substs), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", adt_expr.user_ty), depth_lvl + 1); + + for (i, field_expr) in adt_expr.fields.iter().enumerate() { + print_indented!(self, format!("field {}:", i), depth_lvl + 1); + self.print_expr(field_expr.expr, depth_lvl + 2); + } + + if let Some(ref base) = adt_expr.base { + print_indented!(self, "base:", depth_lvl + 1); + self.print_fru_info(base, depth_lvl + 2); + } else { + print_indented!(self, "base: None", depth_lvl + 1); + } + } + + fn print_adt_def(&mut self, adt_def: ty::AdtDef<'tcx>, depth_lvl: usize) { + print_indented!(self, "AdtDef {", depth_lvl); + print_indented!(self, format!("did: {:?}", adt_def.did()), depth_lvl + 1); + print_indented!(self, format!("variants: {:?}", adt_def.variants()), depth_lvl + 1); + print_indented!(self, format!("flags: {:?}", adt_def.flags()), depth_lvl + 1); + print_indented!(self, format!("repr: {:?}", adt_def.repr()), depth_lvl + 1); + } + + fn print_fru_info(&mut self, fru_info: &FruInfo<'tcx>, depth_lvl: usize) { + print_indented!(self, "FruInfo {", depth_lvl); + print_indented!(self, "base: ", depth_lvl + 1); + self.print_expr(fru_info.base, depth_lvl + 2); + print_indented!(self, "field_types: [", depth_lvl + 1); + for ty in fru_info.field_types.iter() { + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); + } + print_indented!(self, "}", depth_lvl); + } + + fn print_arm(&mut self, arm_id: ArmId, depth_lvl: usize) { + print_indented!(self, "Arm {", depth_lvl); + + let arm = &self.thir.arms[arm_id]; + let Arm { pattern, guard, body, lint_level, scope, span } = arm; + + print_indented!(self, "pattern: ", depth_lvl + 1); + self.print_pat(pattern, depth_lvl + 2); + + if let Some(guard) = guard { + print_indented!(self, "guard: ", depth_lvl + 1); + self.print_guard(guard, depth_lvl + 2); + } else { + print_indented!(self, "guard: None", depth_lvl + 1); + } + + print_indented!(self, "body: ", depth_lvl + 1); + self.print_expr(*body, depth_lvl + 2); + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + + fn print_pat(&mut self, pat: &Box<Pat<'tcx>>, depth_lvl: usize) { + let Pat { ty, span, kind } = &**pat; + + print_indented!(self, "Pat: {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + self.print_pat_kind(kind, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + + fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) { + print_indented!(self, "kind: PatKind {", depth_lvl); + + match pat_kind { + PatKind::Wild => { + print_indented!(self, "Wild", depth_lvl + 1); + } + PatKind::AscribeUserType { ascription, subpattern } => { + print_indented!(self, "AscribeUserType: {", depth_lvl + 1); + print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2); + print_indented!(self, "subpattern: ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => { + print_indented!(self, "Binding {", depth_lvl + 1); + print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2); + print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); + print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2); + print_indented!(self, format!("var: {:?}", var), depth_lvl + 2); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); + print_indented!(self, format!("is_primary: {:?}", is_primary), depth_lvl + 2); + + if let Some(subpattern) = subpattern { + print_indented!(self, "subpattern: Some( ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "subpattern: None", depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Variant { adt_def, substs, variant_index, subpatterns } => { + print_indented!(self, "Variant {", depth_lvl + 1); + print_indented!(self, "adt_def: ", depth_lvl + 2); + self.print_adt_def(*adt_def, depth_lvl + 3); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 2); + print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 2); + + if subpatterns.len() > 0 { + print_indented!(self, "subpatterns: [", depth_lvl + 2); + for field_pat in subpatterns.iter() { + self.print_pat(&field_pat.pattern, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + } else { + print_indented!(self, "subpatterns: []", depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Leaf { subpatterns } => { + print_indented!(self, "Leaf { ", depth_lvl + 1); + print_indented!(self, "subpatterns: [", depth_lvl + 2); + for field_pat in subpatterns.iter() { + self.print_pat(&field_pat.pattern, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Deref { subpattern } => { + print_indented!(self, "Deref { ", depth_lvl + 1); + print_indented!(self, "subpattern: ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Constant { value } => { + print_indented!(self, "Constant {", depth_lvl + 1); + print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Range(pat_range) => { + print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1); + } + PatKind::Slice { prefix, slice, suffix } => { + print_indented!(self, "Slice {", depth_lvl + 1); + + print_indented!(self, "prefix: [", depth_lvl + 2); + for prefix_pat in prefix.iter() { + self.print_pat(prefix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + if let Some(slice) = slice { + print_indented!(self, "slice: ", depth_lvl + 2); + self.print_pat(slice, depth_lvl + 3); + } + + print_indented!(self, "suffix: [", depth_lvl + 2); + for suffix_pat in suffix.iter() { + self.print_pat(suffix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Array { prefix, slice, suffix } => { + print_indented!(self, "Array {", depth_lvl + 1); + + print_indented!(self, "prefix: [", depth_lvl + 2); + for prefix_pat in prefix.iter() { + self.print_pat(prefix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + if let Some(slice) = slice { + print_indented!(self, "slice: ", depth_lvl + 2); + self.print_pat(slice, depth_lvl + 3); + } + + print_indented!(self, "suffix: [", depth_lvl + 2); + for suffix_pat in suffix.iter() { + self.print_pat(suffix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Or { pats } => { + print_indented!(self, "Or {", depth_lvl + 1); + print_indented!(self, "pats: [", depth_lvl + 2); + for pat in pats.iter() { + self.print_pat(pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_guard(&mut self, guard: &Guard<'tcx>, depth_lvl: usize) { + print_indented!(self, "Guard {", depth_lvl); + + match guard { + Guard::If(expr_id) => { + print_indented!(self, "If (", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } + Guard::IfLet(pat, expr_id) => { + print_indented!(self, "IfLet (", depth_lvl + 1); + self.print_pat(pat, depth_lvl + 2); + print_indented!(self, ",", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_closure_expr(&mut self, expr: &ClosureExpr<'tcx>, depth_lvl: usize) { + let ClosureExpr { closure_id, substs, upvars, movability, fake_reads } = expr; + + print_indented!(self, "ClosureExpr {", depth_lvl); + print_indented!(self, format!("closure_id: {:?}", closure_id), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + + if upvars.len() > 0 { + print_indented!(self, "upvars: [", depth_lvl + 1); + for upvar in upvars.iter() { + self.print_expr(*upvar, depth_lvl + 2); + print_indented!(self, ",", depth_lvl + 1); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "upvars: []", depth_lvl + 1); + } + + print_indented!(self, format!("movability: {:?}", movability), depth_lvl + 1); + + if fake_reads.len() > 0 { + print_indented!(self, "fake_reads: [", depth_lvl + 1); + for (fake_read_expr, cause, hir_id) in fake_reads.iter() { + print_indented!(self, "(", depth_lvl + 2); + self.print_expr(*fake_read_expr, depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + print_indented!(self, format!("cause: {:?}", cause), depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 3); + print_indented!(self, "),", depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "fake_reads: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) { + let InlineAsmExpr { template, operands, options, line_spans } = expr; + + print_indented!(self, "InlineAsmExpr {", depth_lvl); + + print_indented!(self, "template: [", depth_lvl + 1); + for template_piece in template.iter() { + print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + + print_indented!(self, "operands: [", depth_lvl + 1); + for operand in operands.iter() { + self.print_inline_operand(operand, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + + print_indented!(self, format!("options: {:?}", options), depth_lvl + 1); + print_indented!(self, format!("line_spans: {:?}", line_spans), depth_lvl + 1); + } + + fn print_inline_operand(&mut self, operand: &InlineAsmOperand<'tcx>, depth_lvl: usize) { + match operand { + InlineAsmOperand::In { reg, expr } => { + print_indented!(self, "InlineAsmOperand::In {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, "expr: ", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::Out { reg, late, expr } => { + print_indented!(self, "InlineAsmOperand::Out {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + + if let Some(out) = expr { + print_indented!(self, "place: Some( ", depth_lvl + 1); + self.print_expr(*out, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "place: None", depth_lvl + 1); + } + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::InOut { reg, late, expr } => { + print_indented!(self, "InlineAsmOperand::InOut {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + print_indented!(self, "expr: ", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { + print_indented!(self, "InlineAsmOperand::SplitInOut {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + print_indented!(self, "in_expr: ", depth_lvl + 1); + self.print_expr(*in_expr, depth_lvl + 2); + + if let Some(out_expr) = out_expr { + print_indented!(self, "out_expr: Some( ", depth_lvl + 1); + self.print_expr(*out_expr, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "out_expr: None", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::Const { value, span } => { + print_indented!(self, "InlineAsmOperand::Const {", depth_lvl); + print_indented!(self, format!("value: {:?}", value), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SymFn { value, span } => { + print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl); + print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SymStatic { def_id } => { + print_indented!(self, "InlineAsmOperand::SymStatic {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + } + } +} |