change is_subtype to relate_types
This commit is contained in:
parent
cd7f471931
commit
6f0c5ee2d4
15 changed files with 128 additions and 86 deletions
|
@ -716,14 +716,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
}
|
||||
PlaceTy::from_ty(fty)
|
||||
}
|
||||
ProjectionElem::Subtype(_) => {
|
||||
let guard = span_mirbug_and_err!(
|
||||
self,
|
||||
place,
|
||||
"ProjectionElem::Subtype shouldn't exist in borrowck"
|
||||
);
|
||||
PlaceTy::from_ty(Ty::new_error(tcx, guard))
|
||||
}
|
||||
ProjectionElem::Subtype(_) => PlaceTy::from_ty(Ty::new_error_with_message(
|
||||
tcx,
|
||||
self.last_span,
|
||||
"ProjectionElem::Subtype shouldn't exist in borrowck",
|
||||
)),
|
||||
ProjectionElem::OpaqueCast(ty) => {
|
||||
let ty = self.sanitize_type(place, ty);
|
||||
let ty = self.cx.normalize(ty, location);
|
||||
|
@ -2564,7 +2561,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
ProjectionElem::Field(..)
|
||||
| ProjectionElem::Subtype(..)
|
||||
| ProjectionElem::Downcast(..)
|
||||
| ProjectionElem::OpaqueCast(..)
|
||||
| ProjectionElem::Index(..)
|
||||
|
@ -2572,6 +2568,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
| ProjectionElem::Subslice { .. } => {
|
||||
// other field access
|
||||
}
|
||||
ProjectionElem::Subtype(_) => {
|
||||
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -876,7 +876,7 @@ pub(crate) fn codegen_place<'tcx>(
|
|||
cplace = cplace.place_deref(fx);
|
||||
}
|
||||
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
|
||||
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, ty),
|
||||
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)),
|
||||
PlaceElem::Field(field, _ty) => {
|
||||
cplace = cplace.place_field(fx, field);
|
||||
}
|
||||
|
|
|
@ -674,12 +674,14 @@ impl<'tcx> CPlace<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Used for `ProjectionElem::Subtype`, ty has to be monomorphized before
|
||||
/// passed on.
|
||||
pub(crate) fn place_transmute_type(
|
||||
self,
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> CPlace<'tcx> {
|
||||
CPlace { inner: self.inner, layout: fx.layout_of(fx.monomorphize(ty)) }
|
||||
CPlace { inner: self.inner, layout: fx.layout_of(ty) }
|
||||
}
|
||||
|
||||
pub(crate) fn place_field(
|
||||
|
|
|
@ -13,7 +13,7 @@ use rustc_middle::ty::layout::{
|
|||
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
|
||||
TyAndLayout,
|
||||
};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance};
|
||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::Span;
|
||||
|
@ -384,7 +384,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
|
|||
// all normal lifetimes are erased, higher-ranked types with their
|
||||
// late-bound lifetimes are still around and can lead to type
|
||||
// differences.
|
||||
if util::is_subtype(tcx, param_env, src.ty, dest.ty) {
|
||||
if util::relate_types(tcx, param_env, Variance::Covariant, src.ty, dest.ty) {
|
||||
// Make sure the layout is equal, too -- just to be safe. Miri really
|
||||
// needs layout equality. For performance reason we skip this check when
|
||||
// the types are equal. Equal types *can* have different layouts when
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_infer::traits::Reveal;
|
|||
use rustc_middle::mir::interpret::Scalar;
|
||||
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance};
|
||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||
use rustc_mir_dataflow::{Analysis, ResultsCursor};
|
||||
|
@ -16,7 +16,7 @@ use rustc_target::spec::abi::Abi;
|
|||
|
||||
use crate::util::is_within_packed;
|
||||
|
||||
use crate::util::is_subtype;
|
||||
use crate::util::relate_types;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum EdgeKind {
|
||||
|
@ -604,7 +604,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
return true;
|
||||
}
|
||||
|
||||
return crate::util::is_subtype(self.tcx, self.param_env, src, dest);
|
||||
// After borrowck subtyping should be fully explicit via
|
||||
// `Subtype` projections.
|
||||
let variance = if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
Variance::Invariant
|
||||
} else {
|
||||
Variance::Covariant
|
||||
};
|
||||
|
||||
crate::util::relate_types(self.tcx, self.param_env, variance, src, dest)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -756,9 +764,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
ProjectionElem::Subtype(ty) => {
|
||||
if !is_subtype(
|
||||
if !relate_types(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
Variance::Covariant,
|
||||
ty,
|
||||
place_ref.ty(&self.body.local_decls, self.tcx).ty,
|
||||
) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::traits::{DefiningAnchor, ObligationCause};
|
||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance};
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
|
||||
/// Returns whether the two types are equal up to subtyping.
|
||||
|
@ -24,16 +24,22 @@ pub fn is_equal_up_to_subtyping<'tcx>(
|
|||
}
|
||||
|
||||
// Check for subtyping in either direction.
|
||||
is_subtype(tcx, param_env, src, dest) || is_subtype(tcx, param_env, dest, src)
|
||||
relate_types(tcx, param_env, Variance::Covariant, src, dest)
|
||||
|| relate_types(tcx, param_env, Variance::Covariant, dest, src)
|
||||
}
|
||||
|
||||
/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
|
||||
///
|
||||
/// For almost all of the use cases variance should be `Covariant`,
|
||||
/// in `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial` variance should
|
||||
/// be `Invariant`.
|
||||
///
|
||||
/// This mostly ignores opaque types as it can be used in constraining contexts
|
||||
/// while still computing the final underlying type.
|
||||
pub fn is_subtype<'tcx>(
|
||||
pub fn relate_types<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
variance: Variance,
|
||||
src: Ty<'tcx>,
|
||||
dest: Ty<'tcx>,
|
||||
) -> bool {
|
||||
|
@ -48,7 +54,7 @@ pub fn is_subtype<'tcx>(
|
|||
let cause = ObligationCause::dummy();
|
||||
let src = ocx.normalize(&cause, param_env, src);
|
||||
let dest = ocx.normalize(&cause, param_env, dest);
|
||||
match ocx.sub(&cause, param_env, src, dest) {
|
||||
match ocx.relate(&cause, param_env, variance, src, dest) {
|
||||
Ok(()) => {}
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ mod type_name;
|
|||
|
||||
pub use self::alignment::{is_disaligned, is_within_packed};
|
||||
pub use self::check_validity_requirement::check_validity_requirement;
|
||||
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
|
||||
pub use self::compare_types::{is_equal_up_to_subtyping, relate_types};
|
||||
pub use self::type_name::type_name;
|
||||
|
||||
/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
|
||||
|
|
|
@ -218,7 +218,13 @@ impl<'tcx> Inliner<'tcx> {
|
|||
// Normally, this shouldn't be required, but trait normalization failure can create a
|
||||
// validation ICE.
|
||||
let output_type = callee_body.return_ty();
|
||||
if !util::is_subtype(self.tcx, self.param_env, output_type, destination_ty) {
|
||||
if !util::relate_types(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
ty::Variance::Covariant,
|
||||
output_type,
|
||||
destination_ty,
|
||||
) {
|
||||
trace!(?output_type, ?destination_ty);
|
||||
return Err("failed to normalize return type");
|
||||
}
|
||||
|
@ -248,7 +254,13 @@ impl<'tcx> Inliner<'tcx> {
|
|||
self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
|
||||
{
|
||||
let input_type = callee_body.local_decls[input].ty;
|
||||
if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
|
||||
if !util::relate_types(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
ty::Variance::Covariant,
|
||||
input_type,
|
||||
arg_ty,
|
||||
) {
|
||||
trace!(?arg_ty, ?input_type);
|
||||
return Err("failed to normalize tuple argument type");
|
||||
}
|
||||
|
@ -257,7 +269,13 @@ impl<'tcx> Inliner<'tcx> {
|
|||
for (arg, input) in args.iter().zip(callee_body.args_iter()) {
|
||||
let input_type = callee_body.local_decls[input].ty;
|
||||
let arg_ty = arg.ty(&caller_body.local_decls, self.tcx);
|
||||
if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
|
||||
if !util::relate_types(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
ty::Variance::Covariant,
|
||||
input_type,
|
||||
arg_ty,
|
||||
) {
|
||||
trace!(?arg_ty, ?input_type);
|
||||
return Err("failed to normalize argument type");
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ use rustc_middle::traits::query::NoSolution;
|
|||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::ToPredicate;
|
||||
use rustc_middle::ty::TypeFoldable;
|
||||
use rustc_middle::ty::Variance;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::config::TraitSolver;
|
||||
|
||||
|
@ -156,6 +157,20 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
|||
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
|
||||
}
|
||||
|
||||
pub fn relate<T: ToTrace<'tcx>>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
variance: Variance,
|
||||
expected: T,
|
||||
actual: T,
|
||||
) -> Result<(), TypeError<'tcx>> {
|
||||
self.infcx
|
||||
.at(cause, param_env)
|
||||
.relate(DefineOpaqueTypes::Yes, expected, variance, actual)
|
||||
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
|
||||
}
|
||||
|
||||
/// Checks whether `expected` is a supertype of `actual`: `expected :> actual`.
|
||||
pub fn sup<T: ToTrace<'tcx>>(
|
||||
&self,
|
||||
|
|
1
src/tools/stable-mir-dev
Submodule
1
src/tools/stable-mir-dev
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 9434648ba82a0519222677bcc3fdf8b4f1ac5ced
|
14
tabula.rs
14
tabula.rs
|
@ -1,14 +0,0 @@
|
|||
// run-pass
|
||||
#![deny(drop_bounds)]
|
||||
// As a special exemption, `impl Drop` in the return position raises no error.
|
||||
// This allows a convenient way to return an unnamed drop guard.
|
||||
fn voldemort_type() -> impl Drop {
|
||||
struct Voldemort;
|
||||
impl Drop for Voldemort {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
Voldemort
|
||||
}
|
||||
fn main() {
|
||||
let _ = voldemort_type();
|
||||
}
|
|
@ -7,12 +7,12 @@
|
|||
let mut _2: std::pin::Pin<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>;
|
||||
let mut _3: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
let mut _4: {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
+ let mut _5: bool;
|
||||
+ let mut _6: bool;
|
||||
scope 1 {
|
||||
debug _r => _1;
|
||||
}
|
||||
+ scope 2 (inlined g) {
|
||||
+ let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8];
|
||||
+ let mut _5: {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
+ }
|
||||
+ scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) {
|
||||
+ debug pointer => _3;
|
||||
|
@ -23,10 +23,10 @@
|
|||
+ }
|
||||
+ }
|
||||
+ scope 6 (inlined g::{closure#0}) {
|
||||
+ debug a => _5;
|
||||
+ let mut _6: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
+ let mut _7: u32;
|
||||
+ let mut _8: i32;
|
||||
+ debug a => _6;
|
||||
+ let mut _7: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
+ let mut _8: u32;
|
||||
+ let mut _9: i32;
|
||||
+ }
|
||||
|
||||
bb0: {
|
||||
|
@ -35,21 +35,24 @@
|
|||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
- _4 = g() -> [return: bb1, unwind unreachable];
|
||||
+ _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
|
||||
+ StorageLive(_5);
|
||||
+ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
|
||||
+ _4 = move (_5as {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
||||
+ StorageDead(_5);
|
||||
+ _3 = &mut _4;
|
||||
+ _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 };
|
||||
+ StorageDead(_3);
|
||||
+ StorageLive(_5);
|
||||
+ _5 = const false;
|
||||
+ _6 = (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
||||
+ _7 = discriminant((*_6));
|
||||
+ switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9];
|
||||
+ StorageLive(_6);
|
||||
+ _6 = const false;
|
||||
+ _7 = (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
||||
+ _8 = discriminant((*_7));
|
||||
+ switchInt(move _8) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
- _3 = &mut _4;
|
||||
- _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind unreachable];
|
||||
+ StorageDead(_5);
|
||||
+ StorageDead(_6);
|
||||
+ StorageDead(_2);
|
||||
+ drop(_4) -> [return: bb2, unwind unreachable];
|
||||
}
|
||||
|
@ -66,8 +69,8 @@
|
|||
bb3: {
|
||||
- StorageDead(_2);
|
||||
- drop(_4) -> [return: bb4, unwind unreachable];
|
||||
+ StorageLive(_8);
|
||||
+ switchInt(_5) -> [0: bb4, otherwise: bb5];
|
||||
+ StorageLive(_9);
|
||||
+ switchInt(_6) -> [0: bb4, otherwise: bb5];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
|
@ -75,18 +78,18 @@
|
|||
- _0 = const ();
|
||||
- StorageDead(_1);
|
||||
- return;
|
||||
+ _8 = const 13_i32;
|
||||
+ _9 = const 13_i32;
|
||||
+ goto -> bb6;
|
||||
+ }
|
||||
+
|
||||
+ bb5: {
|
||||
+ _8 = const 7_i32;
|
||||
+ _9 = const 7_i32;
|
||||
+ goto -> bb6;
|
||||
+ }
|
||||
+
|
||||
+ bb6: {
|
||||
+ _1 = GeneratorState::<i32, bool>::Yielded(move _8);
|
||||
+ discriminant((*_6)) = 3;
|
||||
+ _1 = GeneratorState::<i32, bool>::Yielded(move _9);
|
||||
+ discriminant((*_7)) = 3;
|
||||
+ goto -> bb1;
|
||||
+ }
|
||||
+
|
||||
|
@ -95,10 +98,10 @@
|
|||
+ }
|
||||
+
|
||||
+ bb8: {
|
||||
+ StorageLive(_8);
|
||||
+ StorageDead(_8);
|
||||
+ _1 = GeneratorState::<i32, bool>::Complete(_5);
|
||||
+ discriminant((*_6)) = 1;
|
||||
+ StorageLive(_9);
|
||||
+ StorageDead(_9);
|
||||
+ _1 = GeneratorState::<i32, bool>::Complete(_6);
|
||||
+ discriminant((*_7)) = 1;
|
||||
+ goto -> bb1;
|
||||
+ }
|
||||
+
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
let mut _2: std::pin::Pin<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>;
|
||||
let mut _3: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
let mut _4: {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
+ let mut _5: bool;
|
||||
+ let mut _6: bool;
|
||||
scope 1 {
|
||||
debug _r => _1;
|
||||
}
|
||||
+ scope 2 (inlined g) {
|
||||
+ let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8];
|
||||
+ let mut _5: {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
+ }
|
||||
+ scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) {
|
||||
+ debug pointer => _3;
|
||||
|
@ -23,10 +23,10 @@
|
|||
+ }
|
||||
+ }
|
||||
+ scope 6 (inlined g::{closure#0}) {
|
||||
+ debug a => _5;
|
||||
+ let mut _6: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
+ let mut _7: u32;
|
||||
+ let mut _8: i32;
|
||||
+ debug a => _6;
|
||||
+ let mut _7: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8};
|
||||
+ let mut _8: u32;
|
||||
+ let mut _9: i32;
|
||||
+ }
|
||||
|
||||
bb0: {
|
||||
|
@ -38,7 +38,10 @@
|
|||
- }
|
||||
-
|
||||
- bb1: {
|
||||
+ _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
|
||||
+ StorageLive(_5);
|
||||
+ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
|
||||
+ _4 = move (_5as {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
||||
+ StorageDead(_5);
|
||||
_3 = &mut _4;
|
||||
- _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind: bb5];
|
||||
- }
|
||||
|
@ -47,11 +50,11 @@
|
|||
+ _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 };
|
||||
StorageDead(_3);
|
||||
- _1 = <{generator@$DIR/inline_generator.rs:16:5: 16:8} as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb5];
|
||||
+ StorageLive(_5);
|
||||
+ _5 = const false;
|
||||
+ _6 = (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
||||
+ _7 = discriminant((*_6));
|
||||
+ switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11];
|
||||
+ StorageLive(_6);
|
||||
+ _6 = const false;
|
||||
+ _7 = (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
||||
+ _8 = discriminant((*_7));
|
||||
+ switchInt(move _8) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11];
|
||||
}
|
||||
|
||||
- bb3: {
|
||||
|
@ -82,23 +85,23 @@
|
|||
+ }
|
||||
+
|
||||
+ bb5: {
|
||||
+ StorageLive(_8);
|
||||
+ switchInt(_5) -> [0: bb6, otherwise: bb7];
|
||||
+ StorageLive(_9);
|
||||
+ switchInt(_6) -> [0: bb6, otherwise: bb7];
|
||||
+ }
|
||||
+
|
||||
+ bb6: {
|
||||
+ _8 = const 13_i32;
|
||||
+ _9 = const 13_i32;
|
||||
+ goto -> bb8;
|
||||
+ }
|
||||
+
|
||||
+ bb7: {
|
||||
+ _8 = const 7_i32;
|
||||
+ _9 = const 7_i32;
|
||||
+ goto -> bb8;
|
||||
+ }
|
||||
+
|
||||
+ bb8: {
|
||||
+ _1 = GeneratorState::<i32, bool>::Yielded(move _8);
|
||||
+ discriminant((*_6)) = 3;
|
||||
+ _1 = GeneratorState::<i32, bool>::Yielded(move _9);
|
||||
+ discriminant((*_7)) = 3;
|
||||
+ goto -> bb1;
|
||||
+ }
|
||||
+
|
||||
|
@ -107,10 +110,10 @@
|
|||
+ }
|
||||
+
|
||||
+ bb10: {
|
||||
+ StorageLive(_8);
|
||||
+ StorageDead(_8);
|
||||
+ _1 = GeneratorState::<i32, bool>::Complete(_5);
|
||||
+ discriminant((*_6)) = 1;
|
||||
+ StorageLive(_9);
|
||||
+ StorageDead(_9);
|
||||
+ _1 = GeneratorState::<i32, bool>::Complete(_6);
|
||||
+ discriminant((*_7)) = 1;
|
||||
+ goto -> bb1;
|
||||
+ }
|
||||
+
|
||||
|
|
|
@ -107,7 +107,7 @@ fn main() -> () {
|
|||
_14 = {closure@main::{closure#0}};
|
||||
Retag(_14);
|
||||
_29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
|
||||
_13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32);
|
||||
_13 = move (_29as for<'a> fn(&'a i32) -> &'a i32);
|
||||
StorageDead(_14);
|
||||
StorageLive(_15);
|
||||
StorageLive(_16);
|
||||
|
|
|
@ -107,7 +107,7 @@ fn main() -> () {
|
|||
_14 = {closure@main::{closure#0}};
|
||||
Retag(_14);
|
||||
_29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
|
||||
_13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32);
|
||||
_13 = move (_29as for<'a> fn(&'a i32) -> &'a i32);
|
||||
StorageDead(_14);
|
||||
StorageLive(_15);
|
||||
StorageLive(_16);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue