&sym.qself,
&sym.path,
ParamMode::Optional,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
hir::InlineAsmOperand::SymStatic { path, def_id }
} else {
}
fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
- let ty = l
- .ty
- .as_ref()
- .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
+ let ty = l.ty.as_ref().map(|t| {
+ self.lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Variable))
+ });
let init = l.kind.init().map(|init| self.lower_expr(init));
let hir_id = self.lower_node_id(l.id);
let pat = self.lower_pat(&l.pat);
seg,
ParamMode::Optional,
ParenthesizedGenericArgs::Err,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
));
let receiver = self.lower_expr(receiver);
let args =
}
ExprKind::Cast(ref expr, ref ty) => {
let expr = self.lower_expr(expr);
- let ty =
- self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let ty = self
+ .lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
hir::ExprKind::Cast(expr, ty)
}
ExprKind::Type(ref expr, ref ty) => {
let expr = self.lower_expr(expr);
- let ty =
- self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let ty = self
+ .lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
hir::ExprKind::Type(expr, ty)
}
ExprKind::AddrOf(k, m, ref ohs) => {
qself,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
hir::ExprKind::Path(qpath)
}
&se.qself,
&se.path,
ParamMode::Optional,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
)),
self.arena
.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
async_gen_kind: hir::AsyncGeneratorKind,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'hir> {
- let output = match ret_ty {
- Some(ty) => hir::FnRetTy::Return(
- self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)),
- ),
- None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
- };
+ let output =
+ match ret_ty {
+ Some(ty) => hir::FnRetTy::Return(self.lower_ty(
+ &ty,
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock),
+ )),
+ None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
+ };
// Resume argument type. We let the compiler infer this to simplify the lowering. It is
// fully constrained by `future::from_generator`.
qself,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
// Destructure like a tuple struct.
let tuple_struct_pat =
qself,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
// Destructure like a unit struct.
let unit_struct_pat = hir::PatKind::Path(qpath);
&se.qself,
&se.path,
ParamMode::Optional,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
let fields_omitted = match &se.rest {
StructRest::Base(e) => {
let body_id =
this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
- let itctx = ImplTraitContext::Universal;
- let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
+ let mut itctx = ImplTraitContext::Universal;
+ let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
let ret_id = asyncness.opt_return_id();
this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
});
let (generics, ty) = self.lower_generics(
&generics,
id,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- |this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy),
);
hir::ItemKind::TyAlias(ty, generics)
}
let (generics, ty) = self.lower_generics(
&generics,
id,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
);
hir::ItemKind::TyAlias(ty, generics)
let (generics, variants) = self.lower_generics(
generics,
id,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
this.arena.alloc_from_iter(
enum_definition.variants.iter().map(|x| this.lower_variant(x)),
let (generics, struct_def) = self.lower_generics(
generics,
id,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, struct_def),
);
hir::ItemKind::Struct(struct_def, generics)
let (generics, vdata) = self.lower_generics(
generics,
id,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, vdata),
);
hir::ItemKind::Union(vdata, generics)
// method, it will not be considered an in-band
// lifetime to be added, but rather a reference to a
// parent lifetime.
- let itctx = ImplTraitContext::Universal;
+ let mut itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) =
- self.lower_generics(ast_generics, id, itctx, |this| {
+ self.lower_generics(ast_generics, id, &mut itctx, |this| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
trait_ref,
- ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
)
});
- let lowered_ty = this
- .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let lowered_ty = this.lower_ty(
+ ty,
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+ );
(trait_ref, lowered_ty)
});
let (generics, (unsafety, items, bounds)) = self.lower_generics(
generics,
id,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let bounds = this.lower_param_bounds(
bounds,
- ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
);
let items = this.arena.alloc_from_iter(
items.iter().map(|item| this.lower_trait_item_ref(item)),
let (generics, bounds) = self.lower_generics(
generics,
id,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
this.lower_param_bounds(
bounds,
- ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
)
},
);
span: Span,
body: Option<&Expr>,
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
- let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let ty = self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
(ty, self.lower_const_body(span, body))
}
kind: match i.kind {
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
let fdec = &sig.decl;
- let itctx = ImplTraitContext::Universal;
+ let mut itctx = ImplTraitContext::Universal;
let (generics, (fn_dec, fn_args)) =
- self.lower_generics(generics, i.id, itctx, |this| {
+ self.lower_generics(generics, i.id, &mut itctx, |this| {
(
// Disallow `impl Trait` in foreign items.
this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
}
ForeignItemKind::Static(ref t, m, _) => {
- let ty =
- self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let ty = self
+ .lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
hir::ForeignItemKind::Static(ty, m)
}
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
qself,
path,
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
self.arena.alloc(t)
} else {
- self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+ self.lower_ty(&f.ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type))
};
let hir_id = self.lower_node_id(f.id);
self.lower_attrs(hir_id, &f.attrs);
let (generics, kind, has_default) = match i.kind {
AssocItemKind::Const(_, ref ty, ref default) => {
- let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let ty =
+ self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
}
let (generics, kind) = self.lower_generics(
&generics,
i.id,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = ty.as_ref().map(|x| {
- this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+ this.lower_ty(
+ x,
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+ )
});
hir::TraitItemKind::Type(
this.lower_param_bounds(
bounds,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
),
ty,
)
let (generics, kind) = match &i.kind {
AssocItemKind::Const(_, ty, expr) => {
- let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let ty =
+ self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
(
hir::Generics::empty(),
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
self.lower_generics(
&generics,
i.id,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
None => {
let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
hir::ImplItemKind::TyAlias(ty)
}
Some(ty) => {
- let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
+ let ty = this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy);
hir::ImplItemKind::TyAlias(ty)
}
},
is_async: Option<NodeId>,
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
let header = self.lower_fn_header(sig.header);
- let itctx = ImplTraitContext::Universal;
- let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
+ let mut itctx = ImplTraitContext::Universal;
+ let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| {
this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
});
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
&mut self,
generics: &Generics,
parent_node_id: NodeId,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
f: impl FnOnce(&mut Self) -> T,
) -> (&'hir hir::Generics<'hir>, T) {
debug_assert!(self.impl_trait_defs.is_empty());
id: NodeId,
kind: &GenericParamKind,
bounds: &[GenericBound],
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
origin: PredicateOrigin,
) -> Option<hir::WherePredicate<'hir>> {
// Do not create a clause if we do not have anything inside it.
span,
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
bound_generic_params: self.lower_generic_params(bound_generic_params),
- bounded_ty: self
- .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+ bounded_ty: self.lower_ty(
+ bounded_ty,
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+ ),
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
self.lower_param_bound(
bound,
- ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
)
})),
span: self.lower_span(span),
lifetime: self.lower_lifetime(lifetime),
bounds: self.lower_param_bounds(
bounds,
- ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
),
in_where_clause: true,
}),
WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span }) => {
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
- lhs_ty: self
- .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
- rhs_ty: self
- .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+ lhs_ty: self.lower_ty(
+ lhs_ty,
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+ ),
+ rhs_ty: self.lower_ty(
+ rhs_ty,
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+ ),
span: self.lower_span(span),
})
}
/// actually used in the HIR, as that would trigger an assertion in the
/// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped
/// properly. Calling the method twice with the same `NodeId` is fine though.
+ #[instrument(level = "debug", skip(self), ret)]
fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
assert_ne!(ast_node_id, DUMMY_NODE_ID);
}
/// Generate a new `HirId` without a backing `NodeId`.
+ #[instrument(level = "debug", skip(self), ret)]
fn next_id(&mut self) -> hir::HirId {
let owner = self.current_hir_id_owner;
let local_id = self.item_local_id_counter;
fn lower_assoc_ty_constraint(
&mut self,
constraint: &AssocConstraint,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
// lower generic arguments of identifier in constraint
} else {
self.arena.alloc(hir::GenericArgs::none())
};
+ let mut itctx_tait = ImplTraitContext::TypeAliasesOpaqueTy;
let kind = match constraint.kind {
AssocConstraintKind::Equality { ref term } => {
//
// FIXME: this is only needed until `impl Trait` is allowed in type aliases.
ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => {
- (true, ImplTraitContext::TypeAliasesOpaqueTy)
+ (true, &mut itctx_tait)
}
// We are in the parameter position, but not within a dyn type:
fn lower_generic_arg(
&mut self,
arg: &ast::GenericArg,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> hir::GenericArg<'hir> {
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)),
}
#[instrument(level = "debug", skip(self))]
- fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
+ fn lower_ty(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> &'hir hir::Ty<'hir> {
self.arena.alloc(self.lower_ty_direct(t, itctx))
}
qself: &Option<QSelf>,
path: &Path,
param_mode: ParamMode,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> hir::Ty<'hir> {
// Check whether we should interpret this as a bare trait object.
// This check mirrors the one in late resolution. We only introduce this special case in
self.ty(span, hir::TyKind::Tup(tys))
}
- fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
+ fn lower_ty_direct(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> hir::Ty<'hir> {
let kind = match t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => hir::TyKind::Err,
let span = t.span;
match itctx {
ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
- self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx)
+ self.lower_opaque_impl_trait(span, *origin, def_node_id, bounds, itctx)
}
ImplTraitContext::TypeAliasesOpaqueTy => {
- let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
+ let mut nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
self.lower_opaque_impl_trait(
span,
hir::OpaqueTyOrigin::TyAlias,
def_node_id,
bounds,
- nested_itctx,
+ &mut nested_itctx,
)
}
ImplTraitContext::Universal => {
/// added explicitly in the HIR). But this includes all the lifetimes, and we only want to
/// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters
/// for the lifetimes that get captured (`'x`, in our example above) and reference those.
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
fn lower_opaque_impl_trait(
&mut self,
span: Span,
origin: hir::OpaqueTyOrigin,
opaque_ty_node_id: NodeId,
bounds: &GenericBounds,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> hir::TyKind<'hir> {
// Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop
LifetimeRes::Fresh { param, binder: _ } => {
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
- let old_def_id = self.local_def_id(param);
- if remapping.get(&old_def_id).is_none() {
+ if let Some(old_def_id) = self.opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
let node_id = self.next_node_id();
let new_def_id = self.create_def(
}
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
if fn_node_id.is_some() {
- self.lower_ty_direct(¶m.ty, ImplTraitContext::Universal)
+ self.lower_ty_direct(¶m.ty, &mut ImplTraitContext::Universal)
} else {
self.lower_ty_direct(
¶m.ty,
- ImplTraitContext::Disallowed(match kind {
+ &mut ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn | FnDeclKind::Inherent => {
unreachable!("fn should allow in-band lifetimes")
}
} else {
match decl.output {
FnRetTy::Ty(ref ty) => {
- let context = match fn_node_id {
+ let mut context = match fn_node_id {
Some(fn_node_id) if kind.impl_trait_return_allowed() => {
let fn_def_id = self.local_def_id(fn_node_id);
ImplTraitContext::ReturnPositionOpaqueTy {
FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
}),
};
- hir::FnRetTy::Return(self.lower_ty(ty, context))
+ hir::FnRetTy::Return(self.lower_ty(ty, &mut context))
}
FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
}
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
// `impl Future` opaque type that `async fn` implicitly
// generates.
- let context = ImplTraitContext::ReturnPositionOpaqueTy {
+ let mut context = ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
};
- self.lower_ty(ty, context)
+ self.lower_ty(ty, &mut context)
}
FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
};
fn lower_param_bound(
&mut self,
tpb: &GenericBound,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> hir::GenericBound<'hir> {
match tpb {
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
GenericParamKind::Type { ref default, .. } => {
let kind = hir::GenericParamKind::Type {
default: default.as_ref().map(|x| {
- self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+ self.lower_ty(x, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type))
}),
synthetic: false,
};
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
}
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
- let ty = self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let ty =
+ self.lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let default = default.as_ref().map(|def| self.lower_anon_const(def));
(
hir::ParamName::Plain(self.lower_ident(param.ident)),
}
}
- fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef<'hir> {
+ fn lower_trait_ref(
+ &mut self,
+ p: &TraitRef,
+ itctx: &mut ImplTraitContext,
+ ) -> hir::TraitRef<'hir> {
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
hir::QPath::Resolved(None, path) => path,
qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
fn lower_poly_trait_ref(
&mut self,
p: &PolyTraitRef,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> hir::PolyTraitRef<'hir> {
let bound_generic_params =
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
}
- fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
+ fn lower_mt(&mut self, mt: &MutTy, itctx: &mut ImplTraitContext) -> hir::MutTy<'hir> {
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
}
+ #[instrument(level = "debug", skip(self), ret)]
fn lower_param_bounds(
&mut self,
bounds: &[GenericBound],
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> hir::GenericBounds<'hir> {
self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
}
- fn lower_param_bounds_mut<'s>(
+ fn lower_param_bounds_mut<'s, 'b>(
&'s mut self,
bounds: &'s [GenericBound],
- itctx: ImplTraitContext,
- ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
+ itctx: &'b mut ImplTraitContext,
+ ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> + Captures<'b>
+ {
bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
}
+ #[instrument(level = "debug", skip(self), ret)]
fn lower_generic_and_bounds(
&mut self,
node_id: NodeId,
node_id,
&GenericParamKind::Type { default: None },
bounds,
- ImplTraitContext::Universal,
+ &mut ImplTraitContext::Universal,
hir::PredicateOrigin::ImplTrait,
);
qself,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
break hir::PatKind::TupleStruct(qpath, pats, ddpos);
qself,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
break hir::PatKind::Path(qpath);
}
qself,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
);
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
qself: &Option<QSelf>,
p: &Path,
param_mode: ParamMode,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> hir::QPath<'hir> {
let qself_position = qself.as_ref().map(|q| q.position);
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
segment,
param_mode,
ParenthesizedGenericArgs::Err,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
)
})),
span: self.lower_span(p.span),
segment: &PathSegment,
param_mode: ParamMode,
parenthesized_generic_args: ParenthesizedGenericArgs,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> hir::PathSegment<'hir> {
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
&mut self,
data: &AngleBracketedArgs,
param_mode: ParamMode,
- itctx: ImplTraitContext,
+ itctx: &mut ImplTraitContext,
) -> (GenericArgsCtor<'hir>, bool) {
let has_non_lt_args = data.args.iter().any(|arg| match arg {
AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
// we generally don't permit such things (see #51008).
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
- self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
+ self.lower_ty_direct(
+ ty,
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
+ )
}));
let output_ty = match output {
- FnRetTy::Ty(ty) => {
- self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
- }
+ FnRetTy::Ty(ty) => self
+ .lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
};
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
&name,
),
});
- } else {
- if matches!(
- meta_item.name_or_empty(),
- sym::C | sym::simd | sym::transparent
- ) || int_type_of_word(meta_item.name_or_empty()).is_some()
- {
- recognised = true;
- sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
- span: meta_item.span,
- name: meta_item.name_or_empty().to_ident_string(),
- });
- }
+ } else if matches!(
+ meta_item.name_or_empty(),
+ sym::C | sym::simd | sym::transparent
+ ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+ {
+ recognised = true;
+ sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
+ span: meta_item.span,
+ name: meta_item.name_or_empty().to_ident_string(),
+ });
}
} else if let MetaItemKind::List(_) = meta_item.kind {
if meta_item.has_name(sym::align) {
| mir::StatementKind::Retag { .. }
| mir::StatementKind::AscribeUserType(..)
| mir::StatementKind::Coverage(..)
- | mir::StatementKind::CopyNonOverlapping(..)
+ | mir::StatementKind::Intrinsic(..)
| mir::StatementKind::Nop => {}
}
}
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
+use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{Statement, StatementKind};
StatementKind::FakeRead(box (_, _)) => {
// Only relevant for initialized/liveness/safety checks.
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+ self.consume_operand(location, op);
+ }
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
ref src,
ref dst,
ref count,
- }) => {
+ })) => {
self.consume_operand(location, src);
self.consume_operand(location, dst);
self.consume_operand(location, count);
}
- StatementKind::Nop
+ // Only relevant for mir typeck
+ StatementKind::AscribeUserType(..)
+ // Doesn't have any language semantics
| StatementKind::Coverage(..)
- | StatementKind::AscribeUserType(..)
- | StatementKind::Retag { .. }
- | StatementKind::StorageLive(..) => {
- // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
- // to borrow check.
- }
+ // Does not actually affect borrowck
+ | StatementKind::StorageLive(..) => {}
StatementKind::StorageDead(local) => {
self.access_place(
location,
LocalMutationIsAllowed::Yes,
);
}
- StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+ StatementKind::Nop
+ | StatementKind::Retag { .. }
+ | StatementKind::Deinit(..)
+ | StatementKind::SetDiscriminant { .. } => {
bug!("Statement not allowed in this MIR phase")
}
}
use rustc_index::vec::IndexVec;
use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
use rustc_middle::mir::{
- traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
- PlaceRef, VarDebugInfoContents,
+ traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
+ Place, PlaceElem, PlaceRef, VarDebugInfoContents,
};
use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
flow_state,
);
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
- ..
- }) => {
- span_bug!(
+ StatementKind::Intrinsic(box ref kind) => match kind {
+ NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state),
+ NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
span,
"Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
)
}
- StatementKind::Nop
+ // Only relevant for mir typeck
+ StatementKind::AscribeUserType(..)
+ // Doesn't have any language semantics
| StatementKind::Coverage(..)
- | StatementKind::AscribeUserType(..)
- | StatementKind::Retag { .. }
- | StatementKind::StorageLive(..) => {
- // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
- // to borrow check.
- }
+ // Does not actually affect borrowck
+ | StatementKind::StorageLive(..) => {}
StatementKind::StorageDead(local) => {
self.access_place(
location,
flow_state,
);
}
- StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+ StatementKind::Nop
+ | StatementKind::Retag { .. }
+ | StatementKind::Deinit(..)
+ | StatementKind::SetDiscriminant { .. } => {
bug!("Statement not allowed in this MIR phase")
}
}
);
}
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
- ..
- }) => span_bug!(
- stmt.source_info.span,
- "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics",
- ),
+ StatementKind::Intrinsic(box ref kind) => match kind {
+ NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location),
+ NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
+ stmt.source_info.span,
+ "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics",
+ ),
+ },
StatementKind::FakeRead(..)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::AscribeUserType(..) => {}
StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
- StatementKind::CopyNonOverlapping(inner) => {
- let dst = codegen_operand(fx, &inner.dst);
- let pointee = dst
- .layout()
- .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
- .expect("Expected pointer");
- let dst = dst.load_scalar(fx);
- let src = codegen_operand(fx, &inner.src).load_scalar(fx);
- let count = codegen_operand(fx, &inner.count).load_scalar(fx);
- let elem_size: u64 = pointee.size.bytes();
- let bytes =
- if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
- fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
- }
+ StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic {
+ // We ignore `assume` intrinsics, they are only useful for optimizations
+ NonDivergingIntrinsic::Assume(_) => {}
+ NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
+ src,
+ dst,
+ count,
+ }) => {
+ let dst = codegen_operand(fx, dst);
+ let pointee = dst
+ .layout()
+ .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
+ .expect("Expected pointer");
+ let dst = dst.load_scalar(fx);
+ let src = codegen_operand(fx, src).load_scalar(fx);
+ let count = codegen_operand(fx, count).load_scalar(fx);
+ let elem_size: u64 = pointee.size.bytes();
+ let bytes = if elem_size != 1 {
+ fx.bcx.ins().imul_imm(count, elem_size as i64)
+ } else {
+ count
+ };
+ fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
+ }
+ },
}
}
{
return None;
}
- StatementKind::CopyNonOverlapping(_) => {
- return None;
- } // conservative handling
+ StatementKind::Intrinsic(ref intrinsic) => match **intrinsic {
+ NonDivergingIntrinsic::CopyNonOverlapping(..) => return None,
+ NonDivergingIntrinsic::Assume(..) => {}
+ },
+ // conservative handling
StatementKind::Assign(_)
| StatementKind::FakeRead(_)
| StatementKind::SetDiscriminant { .. }
let usize_layout = fx.layout_of(fx.tcx.types.usize);
match intrinsic {
- sym::assume => {
- intrinsic_args!(fx, args => (_a); intrinsic);
- }
sym::likely | sym::unlikely => {
intrinsic_args!(fx, args => (a); intrinsic);
None
}
- fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> {
- self.const_undef(self.type_ix(0))
- }
-
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
match cv {
})
}
- fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value {
- self.const_undef(self.type_ix(0))
- }
-
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
match cv {
use rustc_arena::TypedArena;
use rustc_ast::CRATE_NODE_ID;
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{ErrorGuaranteed, Handler};
/// that are necessary for the linking. They are only present in symbol table but not actually
/// used in any sections, so the linker will therefore pick relevant rlibs for linking, but
/// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections.
+///
+/// There's a few internal crates in the standard library (aka libcore and
+/// libstd) which actually have a circular dependence upon one another. This
+/// currently arises through "weak lang items" where libcore requires things
+/// like `rust_begin_unwind` but libstd ends up defining it. To get this
+/// circular dependence to work correctly we declare some of these things
+/// in this synthetic object.
fn add_linked_symbol_object(
cmd: &mut dyn Linker,
sess: &Session,
// crates.
let deps = &codegen_results.crate_info.used_crates;
- // There's a few internal crates in the standard library (aka libcore and
- // libstd) which actually have a circular dependence upon one another. This
- // currently arises through "weak lang items" where libcore requires things
- // like `rust_begin_unwind` but libstd ends up defining it. To get this
- // circular dependence to work correctly in all situations we'll need to be
- // sure to correctly apply the `--start-group` and `--end-group` options to
- // GNU linkers, otherwise if we don't use any other symbol from the standard
- // library it'll get discarded and the whole application won't link.
- //
- // In this loop we're calculating the `group_end`, after which crate to
- // pass `--end-group` and `group_start`, before which crate to pass
- // `--start-group`. We currently do this by passing `--end-group` after
- // the first crate (when iterating backwards) that requires a lang item
- // defined somewhere else. Once that's set then when we've defined all the
- // necessary lang items we'll pass `--start-group`.
- //
- // Note that this isn't amazing logic for now but it should do the trick
- // for the current implementation of the standard library.
- let mut group_end = None;
- let mut group_start = None;
- // Crates available for linking thus far.
- let mut available = FxHashSet::default();
- // Crates required to satisfy dependencies discovered so far.
- let mut required = FxHashSet::default();
-
- let info = &codegen_results.crate_info;
- for &cnum in deps.iter().rev() {
- if let Some(missing) = info.missing_lang_items.get(&cnum) {
- let missing_crates = missing.iter().map(|i| info.lang_item_to_crate.get(i).copied());
- required.extend(missing_crates);
- }
-
- required.insert(Some(cnum));
- available.insert(Some(cnum));
-
- if required.len() > available.len() && group_end.is_none() {
- group_end = Some(cnum);
- }
- if required.len() == available.len() && group_end.is_some() {
- group_start = Some(cnum);
- break;
- }
- }
-
- // If we didn't end up filling in all lang items from upstream crates then
- // we'll be filling it in with our crate. This probably means we're the
- // standard library itself, so skip this for now.
- if group_end.is_some() && group_start.is_none() {
- group_end = None;
- }
-
let mut compiler_builtins = None;
let search_path = OnceCell::new();
for &cnum in deps.iter() {
- if group_start == Some(cnum) {
- cmd.group_start();
- }
-
// We may not pass all crates through to the linker. Some crates may
// appear statically in an existing dylib, meaning we'll pick up all the
// symbols from the dylib.
bundle: Some(false),
whole_archive: Some(false) | None,
} => {
+ // HACK/FIXME: Fixup a circular dependency between libgcc and libc
+ // with glibc. This logic should be moved to the libc crate.
+ if sess.target.os == "linux"
+ && sess.target.env == "gnu"
+ && name == "c"
+ {
+ cmd.link_staticlib("gcc", false);
+ }
cmd.link_staticlib(name, lib.verbatim.unwrap_or(false));
}
NativeLibKind::LinkArg => {
}
Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0),
}
-
- if group_end == Some(cnum) {
- cmd.group_end();
- }
}
// compiler-builtins are always placed last to ensure that they're
fn no_default_libraries(&mut self);
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
fn subsystem(&mut self, subsystem: &str);
- fn group_start(&mut self);
- fn group_end(&mut self);
fn linker_plugin_lto(&mut self);
fn add_eh_frame_header(&mut self) {}
fn add_no_exec(&mut self) {}
self.hint_dynamic(); // Reset to default before returning the composed command line.
}
- fn group_start(&mut self) {
- if self.takes_hints() {
- self.linker_arg("--start-group");
- }
- }
-
- fn group_end(&mut self) {
- if self.takes_hints() {
- self.linker_arg("--end-group");
- }
- }
-
fn linker_plugin_lto(&mut self) {
match self.sess.opts.cg.linker_plugin_lto {
LinkerPluginLto::Disabled => {
}
}
- // MSVC doesn't need group indicators
- fn group_start(&mut self) {}
- fn group_end(&mut self) {}
-
fn linker_plugin_lto(&mut self) {
// Do nothing
}
// noop
}
- // Appears not necessary on Emscripten
- fn group_start(&mut self) {}
- fn group_end(&mut self) {}
-
fn linker_plugin_lto(&mut self) {
// Do nothing
}
fn subsystem(&mut self, _subsystem: &str) {}
- // Not needed for now with LLD
- fn group_start(&mut self) {}
- fn group_end(&mut self) {}
-
fn linker_plugin_lto(&mut self) {
// Do nothing for now
}
self.hint_static(); // Reset to default before returning the composed command line.
}
- fn group_start(&mut self) {
- self.cmd.arg("--start-group");
- }
-
- fn group_end(&mut self) {
- self.cmd.arg("--end-group");
- }
-
fn linker_plugin_lto(&mut self) {}
fn control_flow_guard(&mut self) {}
fn subsystem(&mut self, _subsystem: &str) {}
- fn group_start(&mut self) {}
-
- fn group_end(&mut self) {}
-
fn linker_plugin_lto(&mut self) {}
}
fn subsystem(&mut self, _subsystem: &str) {}
- fn group_start(&mut self) {}
-
- fn group_end(&mut self) {}
-
fn linker_plugin_lto(&mut self) {}
}
use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
use rustc_attr as attr;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_data_structures::sync::par_iter;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
+use rustc_hir::weak_lang_items::WEAK_ITEMS_SYMBOLS;
use rustc_index::vec::Idx;
use rustc_metadata::EncodedMetadata;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::exported_symbols;
+use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_middle::middle::lang_items;
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
use rustc_session::Session;
use rustc_span::symbol::sym;
+use rustc_span::Symbol;
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
use rustc_target::abi::{Align, VariantIdx};
crate_name: Default::default(),
used_crates,
used_crate_source: Default::default(),
- lang_item_to_crate: Default::default(),
- missing_lang_items: Default::default(),
dependency_formats: tcx.dependency_formats(()).clone(),
windows_subsystem,
natvis_debugger_visualizers: Default::default(),
};
- let lang_items = tcx.lang_items();
-
let crates = tcx.crates(());
let n_crates = crates.len();
info.native_libraries.reserve(n_crates);
info.crate_name.reserve(n_crates);
info.used_crate_source.reserve(n_crates);
- info.missing_lang_items.reserve(n_crates);
for &cnum in crates.iter() {
info.native_libraries
if tcx.is_no_builtins(cnum) {
info.is_no_builtins.insert(cnum);
}
- let missing = tcx.missing_lang_items(cnum);
- for &item in missing.iter() {
- if let Ok(id) = lang_items.require(item) {
- info.lang_item_to_crate.insert(item, id.krate);
- }
- }
+ }
- // No need to look for lang items that don't actually need to exist.
- let missing =
- missing.iter().cloned().filter(|&l| lang_items::required(tcx, l)).collect();
- info.missing_lang_items.insert(cnum, missing);
+ // Handle circular dependencies in the standard library.
+ // See comment before `add_linked_symbol_object` function for the details.
+ // With msvc-like linkers it's both unnecessary (they support circular dependencies),
+ // and causes linking issues (when weak lang item symbols are "privatized" by LTO).
+ let target = &tcx.sess.target;
+ if !target.is_like_msvc {
+ let missing_weak_lang_items: FxHashSet<&Symbol> = info
+ .used_crates
+ .iter()
+ .flat_map(|cnum| {
+ tcx.missing_lang_items(*cnum)
+ .iter()
+ .filter(|l| lang_items::required(tcx, **l))
+ .filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item))
+ })
+ .collect();
+ let prefix = if target.is_like_windows && target.arch == "x86" { "_" } else { "" };
+ info.linked_symbols
+ .iter_mut()
+ .filter(|(crate_type, _)| {
+ !matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)
+ })
+ .for_each(|(_, linked_symbols)| {
+ linked_symbols.extend(
+ missing_weak_lang_items
+ .iter()
+ .map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)),
+ )
+ });
}
let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type {
}
});
- if tcx.sess.target.is_like_msvc && embed_visualizers {
+ if target.is_like_msvc && embed_visualizers {
info.natvis_debugger_visualizers =
collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis);
}
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_hir::def_id::CrateNum;
-use rustc_hir::LangItem;
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::middle::dependency_format::Dependencies;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
pub used_libraries: Vec<NativeLib>,
pub used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>,
pub used_crates: Vec<CrateNum>,
- pub lang_item_to_crate: FxHashMap<LangItem, CrateNum>,
- pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
pub dependency_formats: Lrc<Dependencies>,
pub windows_subsystem: Option<String>,
pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,
let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
let llval = match name {
- sym::assume => {
- bx.assume(args[0].immediate());
- return;
- }
sym::abort => {
bx.abort();
return;
) -> Self {
let layout = bx.layout_of(ty);
- if layout.is_zst() {
- return OperandRef::new_zst(bx, layout);
- }
-
let val = match val {
ConstValue::Scalar(x) => {
let Abi::Scalar(scalar) = layout.abi else {
let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
OperandValue::Immediate(llval)
}
- ConstValue::ZeroSized => {
- let llval = bx.zst_to_backend(bx.immediate_backend_type(layout));
- OperandValue::Immediate(llval)
- }
+ ConstValue::ZeroSized => return OperandRef::new_zst(bx, layout),
ConstValue::Slice { data, start, end } => {
let Abi::ScalarPair(a_scalar, _) = layout.abi else {
bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
use rustc_middle::mir;
+use rustc_middle::mir::NonDivergingIntrinsic;
use super::FunctionCx;
use super::LocalRef;
self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
bx
}
- mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
- ref src,
- ref dst,
- ref count,
- }) => {
+ mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
+ let op_val = self.codegen_operand(&mut bx, op);
+ bx.assume(op_val.immediate());
+ bx
+ }
+ mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+ mir::CopyNonOverlapping { ref count, ref src, ref dst },
+ )) => {
let dst_val = self.codegen_operand(&mut bx, dst);
let src_val = self.codegen_operand(&mut bx, src);
let count = self.codegen_operand(&mut bx, count).immediate();
fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
- fn zst_to_backend(&self, llty: Self::Type) -> Self::Value;
fn from_const_alloc(
&self,
layout: TyAndLayout<'tcx>,
use rustc_middle::mir::{
self,
interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar},
- BinOp,
+ BinOp, NonDivergingIntrinsic,
};
use rustc_middle::ty;
use rustc_middle::ty::layout::LayoutOf as _;
// These just return their argument
self.copy_op(&args[0], dest, /*allow_transmute*/ false)?;
}
- sym::assume => {
- let cond = self.read_scalar(&args[0])?.to_bool()?;
- if !cond {
- throw_ub_format!("`assume` intrinsic called with `false`");
- }
- }
sym::raw_eq => {
let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
self.write_scalar(result, dest)?;
Ok(true)
}
+ pub(super) fn emulate_nondiverging_intrinsic(
+ &mut self,
+ intrinsic: &NonDivergingIntrinsic<'tcx>,
+ ) -> InterpResult<'tcx> {
+ match intrinsic {
+ NonDivergingIntrinsic::Assume(op) => {
+ let op = self.eval_operand(op, None)?;
+ let cond = self.read_scalar(&op)?.to_bool()?;
+ if !cond {
+ throw_ub_format!("`assume` called with `false`");
+ }
+ Ok(())
+ }
+ NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
+ count,
+ src,
+ dst,
+ }) => {
+ let src = self.eval_operand(src, None)?;
+ let dst = self.eval_operand(dst, None)?;
+ let count = self.eval_operand(count, None)?;
+ self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)
+ }
+ }
+ }
+
pub fn exact_div(
&mut self,
a: &ImmTy<'tcx, M::Provenance>,
M::retag(self, *kind, &dest)?;
}
- // Call CopyNonOverlapping
- CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => {
- let src = self.eval_operand(src, None)?;
- let dst = self.eval_operand(dst, None)?;
- let count = self.eval_operand(count, None)?;
- self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
- }
+ Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
// Statements we do not track.
AscribeUserType(..) => {}
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
- | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::Nop => {}
}
}
use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
- traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location,
- MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, RuntimePhase, Rvalue,
- SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
+ traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping,
+ Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef,
+ ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+ TerminatorKind, UnOp, START_BLOCK,
};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::subst::Subst;
);
}
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
- ref src,
- ref dst,
- ref count,
- }) => {
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+ let ty = op.ty(&self.body.local_decls, self.tcx);
+ if !ty.is_bool() {
+ self.fail(
+ location,
+ format!("`assume` argument must be `bool`, but got: `{}`", ty),
+ );
+ }
+ }
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+ CopyNonOverlapping { src, dst, count },
+ )) => {
let src_ty = src.ty(&self.body.local_decls, self.tcx);
let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) {
src_deref.ty
map
});
+pub static WEAK_ITEMS_SYMBOLS: LazyLock<FxIndexMap<LangItem, Symbol>> = LazyLock::new(|| {
+ let mut map = FxIndexMap::default();
+ $(map.insert(LangItem::$item, sym::$sym);)*
+ map
+});
+
pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol>
{
lang_items::extract(attrs).and_then(|(name, _)| {
Some(values) => {
let values = self.resolve_vars_if_possible(values);
let (is_simple_error, exp_found) = match values {
- ValuePairs::Terms(infer::ExpectedFound {
- expected: ty::Term::Ty(expected),
- found: ty::Term::Ty(found),
- }) => {
- let is_simple_err = expected.is_simple_text() && found.is_simple_text();
- OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
- .report(diag);
-
- (
- is_simple_err,
- Mismatch::Variable(infer::ExpectedFound { expected, found }),
- )
+ ValuePairs::Terms(infer::ExpectedFound { expected, found }) => {
+ match (expected.unpack(), found.unpack()) {
+ (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
+ let is_simple_err =
+ expected.is_simple_text() && found.is_simple_text();
+ OpaqueTypesVisitor::visit_expected_found(
+ self.tcx, expected, found, span,
+ )
+ .report(diag);
+
+ (
+ is_simple_err,
+ Mismatch::Variable(infer::ExpectedFound { expected, found }),
+ )
+ }
+ (ty::TermKind::Const(_), ty::TermKind::Const(_)) => {
+ (false, Mismatch::Fixed("constant"))
+ }
+ _ => (false, Mismatch::Fixed("type")),
+ }
}
- ValuePairs::Terms(infer::ExpectedFound {
- expected: ty::Term::Const(_),
- found: ty::Term::Const(_),
- }) => (false, Mismatch::Fixed("constant")),
ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
(false, Mismatch::Fixed("trait"))
}
ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
- _ => (false, Mismatch::Fixed("type")),
};
let vals = match self.values_str(values) {
Some((expected, found)) => Some((expected, found)),
return None;
}
- Some(match (exp_found.expected, exp_found.found) {
- (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found),
- (expected, found) => (
- DiagnosticStyledString::highlighted(expected.to_string()),
- DiagnosticStyledString::highlighted(found.to_string()),
+ Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
+ (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found),
+ _ => (
+ DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
+ DiagnosticStyledString::highlighted(exp_found.found.to_string()),
),
})
}
impl<'tcx> ValuePairs<'tcx> {
pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
- if let ValuePairs::Terms(ExpectedFound {
- expected: ty::Term::Ty(expected),
- found: ty::Term::Ty(found),
- }) = self
+ if let ValuePairs::Terms(ExpectedFound { expected, found }) = self
+ && let Some(expected) = expected.ty()
+ && let Some(found) = found.ty()
{
- Some((*expected, *found))
+ Some((expected, found))
} else {
None
}
}
}
+ #[instrument(level = "debug", skip(self))]
fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
- debug!("param_bound(param_ty={:?})", param_ty);
-
// Start with anything like `T: 'a` we can scrape from the
// environment. If the environment contains something like
// `for<'a> T: 'a`, then we know that `T` outlives everything.
let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
+ debug!(?declared_bounds_from_env);
let mut param_bounds = vec![];
for declared_bound in declared_bounds_from_env {
let bound_region = declared_bound.map_bound(|outlives| outlives.1);
param_bounds.push(VerifyBound::OutlivedBy(region));
} else {
// This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
+ debug!("found that {param_ty:?} outlives any lifetime, returning empty vector");
return VerifyBound::AllBounds(vec![]);
}
}
// Add in the default bound of fn body that applies to all in
// scope type parameters:
if let Some(r) = self.implicit_region_bound {
+ debug!("adding implicit region bound of {r:?}");
param_bounds.push(VerifyBound::OutlivedBy(r));
}
// Account for explicitly marked-to-track files
// (e.g. accessed in proc macros).
let file_depinfo = sess.parse_sess.file_depinfo.borrow();
- let extra_tracked_files = file_depinfo.iter().map(|path_sym| {
- let path = PathBuf::from(path_sym.as_str());
+
+ let normalize_path = |path: PathBuf| {
let file = FileName::from(path);
escape_dep_filename(&file.prefer_local().to_string())
- });
+ };
+
+ let extra_tracked_files =
+ file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str())));
files.extend(extra_tracked_files);
+ // We also need to track used PGO profile files
+ if let Some(ref profile_instr) = sess.opts.cg.profile_use {
+ files.push(normalize_path(profile_instr.as_path().to_path_buf()));
+ }
+ if let Some(ref profile_sample) = sess.opts.unstable_opts.profile_sample_use {
+ files.push(normalize_path(profile_sample.as_path().to_path_buf()));
+ }
+
if sess.binary_dep_depinfo() {
if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend {
if backend.contains('.') {
write!(fmt, "Coverage::{:?} for {:?}", kind, rgn)
}
Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
- CopyNonOverlapping(box crate::mir::CopyNonOverlapping {
- ref src,
- ref dst,
- ref count,
- }) => {
- write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count)
- }
+ Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
Nop => write!(fmt, "nop"),
}
}
/// It's guaranteed to be in the first place
pub fn has_deref(&self) -> bool {
// To make sure this is not accidently used in wrong mir phase
- debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref));
+ debug_assert!(
+ self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
+ );
self.projection.first() == Some(&PlaceElem::Deref)
}
Retag(..) => "Retag",
AscribeUserType(..) => "AscribeUserType",
Coverage(..) => "Coverage",
- CopyNonOverlapping(..) => "CopyNonOverlapping",
+ Intrinsic(..) => "Intrinsic",
Nop => "Nop",
}
}
/// executed.
Coverage(Box<Coverage>),
+ /// Denotes a call to an intrinsic that does not require an unwind path and always returns.
+ /// This avoids adding a new block and a terminator for simple intrinsics.
+ Intrinsic(Box<NonDivergingIntrinsic<'tcx>>),
+
+ /// No-op. Useful for deleting instructions without affecting statement indices.
+ Nop,
+}
+
+#[derive(
+ Clone,
+ TyEncodable,
+ TyDecodable,
+ Debug,
+ PartialEq,
+ Hash,
+ HashStable,
+ TypeFoldable,
+ TypeVisitable
+)]
+pub enum NonDivergingIntrinsic<'tcx> {
+ /// Denotes a call to the intrinsic function `assume`.
+ ///
+ /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its
+ /// computation to infer information about other variables. So if the boolean came from a
+ /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks.
+ /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`.
+ Assume(Operand<'tcx>),
+
/// Denotes a call to the intrinsic function `copy_nonoverlapping`.
///
/// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer,
///
/// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved?
/// I vaguely remember Ralf saying somewhere that he thought it should not be.
- CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
+ CopyNonOverlapping(CopyNonOverlapping<'tcx>),
+}
- /// No-op. Useful for deleting instructions without affecting statement indices.
- Nop,
+impl std::fmt::Display for NonDivergingIntrinsic<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Assume(op) => write!(f, "assume({op:?})"),
+ Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+ write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
+ }
+ }
+ }
}
/// Describes what kind of retag is to be performed.
location
)
}
- StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{
- src,
- dst,
- count,
- }) => {
- self.visit_operand(src, location);
- self.visit_operand(dst, location);
- self.visit_operand(count, location)
+ StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => {
+ match intrinsic {
+ NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location),
+ NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+ self.visit_operand(src, location);
+ self.visit_operand(dst, location);
+ self.visit_operand(count, location);
+ }
+ }
}
StatementKind::Nop => {}
}
use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
+use crate::ty::{self, InferConst, Ty, TypeFlags};
use std::slice;
#[derive(Debug)]
}
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
self.add_projection_ty(projection_ty);
- match term {
- Term::Ty(ty) => self.add_ty(ty),
- Term::Const(c) => self.add_const(c),
+ match term.unpack() {
+ ty::TermKind::Ty(ty) => self.add_ty(ty),
+ ty::TermKind::Const(c) => self.add_const(c),
}
}
ty::PredicateKind::WellFormed(arg) => {
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
self.add_substs(projection.substs);
- match projection.term {
- ty::Term::Ty(ty) => self.add_ty(ty),
- ty::Term::Const(ct) => self.add_const(ct),
+ match projection.term.unpack() {
+ ty::TermKind::Ty(ty) => self.add_ty(ty),
+ ty::TermKind::Const(ct) => self.add_const(ct),
}
}
}
}
+ #[instrument(level = "debug", skip(self, tcx))]
fn instantiate_into(
&self,
tcx: TyCtxt<'tcx>,
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
+use rustc_serialize::{Decodable, Encodable};
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{ExpnId, Span};
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+use std::mem;
+use std::num::NonZeroUsize;
use std::ops::ControlFlow;
use std::{fmt, str};
outer_exclusive_binder: ty::DebruijnIndex,
}
-// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(TyS<'_>, 40);
-
-// We are actually storing a stable hash cache next to the type, so let's
-// also check the full size
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(WithStableHash<TyS<'_>>, 56);
-
/// Use this rather than `TyS`, whenever possible.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
#[rustc_diagnostic_item = "Ty"]
outer_exclusive_binder: ty::DebruijnIndex,
}
-// This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PredicateS<'_>, 56);
-
/// Use this rather than `PredicateS`, whenever possible.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[rustc_pass_by_value]
}
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
-pub enum Term<'tcx> {
- Ty(Ty<'tcx>),
- Const(Const<'tcx>),
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Term<'tcx> {
+ ptr: NonZeroUsize,
+ marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
}
impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
fn from(ty: Ty<'tcx>) -> Self {
- Term::Ty(ty)
+ TermKind::Ty(ty).pack()
}
}
impl<'tcx> From<Const<'tcx>> for Term<'tcx> {
fn from(c: Const<'tcx>) -> Self {
- Term::Const(c)
+ TermKind::Const(c).pack()
+ }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Term<'tcx> {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ self.unpack().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Term<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(self.unpack().try_fold_with(folder)?.pack())
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Term<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.unpack().visit_with(visitor)
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Term<'tcx> {
+ fn encode(&self, e: &mut E) {
+ self.unpack().encode(e)
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Term<'tcx> {
+ fn decode(d: &mut D) -> Self {
+ let res: TermKind<'tcx> = Decodable::decode(d);
+ res.pack()
}
}
impl<'tcx> Term<'tcx> {
+ #[inline]
+ pub fn unpack(self) -> TermKind<'tcx> {
+ let ptr = self.ptr.get();
+ // SAFETY: use of `Interned::new_unchecked` here is ok because these
+ // pointers were originally created from `Interned` types in `pack()`,
+ // and this is just going in the other direction.
+ unsafe {
+ match ptr & TAG_MASK {
+ TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked(
+ &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
+ ))),
+ CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
+ &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
+ ))),
+ _ => core::intrinsics::unreachable(),
+ }
+ }
+ }
+
pub fn ty(&self) -> Option<Ty<'tcx>> {
- if let Term::Ty(ty) = self { Some(*ty) } else { None }
+ if let TermKind::Ty(ty) = self.unpack() { Some(ty) } else { None }
}
pub fn ct(&self) -> Option<Const<'tcx>> {
- if let Term::Const(c) = self { Some(*c) } else { None }
+ if let TermKind::Const(c) = self.unpack() { Some(c) } else { None }
}
pub fn into_arg(self) -> GenericArg<'tcx> {
- match self {
- Term::Ty(ty) => ty.into(),
- Term::Const(c) => c.into(),
+ match self.unpack() {
+ TermKind::Ty(ty) => ty.into(),
+ TermKind::Const(c) => c.into(),
}
}
}
+const TAG_MASK: usize = 0b11;
+const TYPE_TAG: usize = 0b00;
+const CONST_TAG: usize = 0b01;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub enum TermKind<'tcx> {
+ Ty(Ty<'tcx>),
+ Const(Const<'tcx>),
+}
+
+impl<'tcx> TermKind<'tcx> {
+ #[inline]
+ fn pack(self) -> Term<'tcx> {
+ let (tag, ptr) = match self {
+ TermKind::Ty(ty) => {
+ // Ensure we can use the tag bits.
+ assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
+ (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
+ }
+ TermKind::Const(ct) => {
+ // Ensure we can use the tag bits.
+ assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
+ (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
+ }
+ };
+
+ Term { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData }
+ }
+}
+
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
///
pub variant: Option<VariantIdx>,
pub fields: &'tcx [ty::Const<'tcx>],
}
+
+// Some types are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // These are in alphabetical order, which is easy to maintain.
+ static_assert_size!(PredicateS<'_>, 48);
+ static_assert_size!(TyS<'_>, 40);
+ static_assert_size!(WithStableHash<TyS<'_>>, 56);
+}
use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
use crate::ty::{
- self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable,
+ self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable,
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
};
use rustc_apfloat::ieee::{Double, Single};
}
p!(")");
- if let Term::Ty(ty) = return_ty.skip_binder() {
+ if let Some(ty) = return_ty.skip_binder().ty() {
if !ty.is_unit() {
p!(" -> ", print(return_ty));
}
p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
- match term {
- Term::Ty(ty) => {
- p!(print(ty))
- }
- Term::Const(c) => {
- p!(print(c));
- }
+ match term.unpack() {
+ TermKind::Ty(ty) => p!(print(ty)),
+ TermKind::Const(c) => p!(print(c)),
};
}
}
ty::Term<'tcx> {
- match self {
- ty::Term::Ty(ty) => p!(print(ty)),
- ty::Term::Const(c) => p!(print(c)),
+ match self.unpack() {
+ ty::TermKind::Ty(ty) => p!(print(ty)),
+ ty::TermKind::Const(c) => p!(print(c)),
}
}
use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
-use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
use rustc_hir as ast;
use rustc_hir::def_id::DefId;
use rustc_span::DUMMY_SP;
}
}
-impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
+impl<'tcx> Relate<'tcx> for Term<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: Self,
b: Self,
) -> RelateResult<'tcx, Self> {
- Ok(match (a, b) {
- (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
- (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
+ Ok(match (a.unpack(), b.unpack()) {
+ (TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(),
+ (TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(),
_ => return Err(TypeError::Mismatch),
})
}
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
use rustc_data_structures::functor::IdFunctor;
use rustc_hir as hir;
use rustc_hir::def::Namespace;
impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
type Lifted = ty::Term<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- Some(match self {
- Term::Ty(ty) => Term::Ty(tcx.lift(ty)?),
- Term::Const(c) => Term::Const(tcx.lift(c)?),
- })
+ Some(
+ match self.unpack() {
+ TermKind::Ty(ty) => TermKind::Ty(tcx.lift(ty)?),
+ TermKind::Const(c) => TermKind::Const(tcx.lift(c)?),
+ }
+ .pack(),
+ )
}
}
}
};
- substs.iter().rev().chain(opt_ty.map(|term| match term {
- ty::Term::Ty(ty) => ty.into(),
- ty::Term::Const(ct) => ct.into(),
+ substs.iter().rev().chain(opt_ty.map(|term| match term.unpack() {
+ ty::TermKind::Ty(ty) => ty.into(),
+ ty::TermKind::Const(ct) => ct.into(),
}))
}));
}
| StatementKind::Retag(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
- | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::Nop => None,
};
if let Some(destination) = destination {
| StatementKind::FakeRead(..)
| StatementKind::Nop
| StatementKind::Retag(..)
- | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::StorageLive(..) => {}
}
}
StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
- | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::Nop => {}
}
}
// safe (at least as emitted during MIR construction)
}
- StatementKind::CopyNonOverlapping(..) => unreachable!(),
+ // Move to above list once mir construction uses it.
+ StatementKind::Intrinsic(..) => unreachable!(),
}
self.super_statement(statement, location);
}
// Retain spans from all other statements
StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
- | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::Assign(_)
| StatementKind::SetDiscriminant { .. }
| StatementKind::Deinit(..)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Coverage(_)
- | StatementKind::CopyNonOverlapping(_)
+ | StatementKind::Intrinsic(_)
| StatementKind::Nop => (),
StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
| StatementKind::FakeRead(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
- | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::Nop => {}
}
}
| StatementKind::Retag(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
- | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::Nop => {}
}
}
let mut args = args.drain(..);
block.statements.push(Statement {
source_info: terminator.source_info,
- kind: StatementKind::CopyNonOverlapping(Box::new(
- rustc_middle::mir::CopyNonOverlapping {
- src: args.next().unwrap(),
- dst: args.next().unwrap(),
- count: args.next().unwrap(),
- },
+ kind: StatementKind::Intrinsic(Box::new(
+ NonDivergingIntrinsic::CopyNonOverlapping(
+ rustc_middle::mir::CopyNonOverlapping {
+ src: args.next().unwrap(),
+ dst: args.next().unwrap(),
+ count: args.next().unwrap(),
+ },
+ ),
+ )),
+ });
+ assert_eq!(
+ args.next(),
+ None,
+ "Extra argument for copy_non_overlapping intrinsic"
+ );
+ drop(args);
+ terminator.kind = TerminatorKind::Goto { target };
+ }
+ sym::assume => {
+ let target = target.unwrap();
+ let mut args = args.drain(..);
+ block.statements.push(Statement {
+ source_info: terminator.source_info,
+ kind: StatementKind::Intrinsic(Box::new(
+ NonDivergingIntrinsic::Assume(args.next().unwrap()),
)),
});
assert_eq!(
StatementKind::Assign { .. }
| StatementKind::SetDiscriminant { .. }
| StatementKind::Deinit(..)
- | StatementKind::CopyNonOverlapping(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::Retag { .. } => {
return false;
}
| StatementKind::AscribeUserType(_, _)
| StatementKind::Coverage(_)
| StatementKind::StorageDead(_)
- | StatementKind::CopyNonOverlapping(_)
+ | StatementKind::Intrinsic(_)
| StatementKind::Nop => {}
}
}
| StatementKind::Retag(_, _)
| StatementKind::AscribeUserType(_, _)
| StatementKind::Coverage(_)
- | StatementKind::CopyNonOverlapping(_)
+ | StatementKind::Intrinsic(_)
| StatementKind::Nop => {}
// If the discriminant is set, it is always set
impl<'tcx> Visitor<'tcx> for UsedLocals {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match statement.kind {
- StatementKind::CopyNonOverlapping(..)
+ StatementKind::Intrinsic(..)
| StatementKind::Retag(..)
| StatementKind::Coverage(..)
| StatementKind::FakeRead(..)
open_delim_span: Span,
) -> PResult<'a, ()> {
if self.token.kind == token::Comma {
+ if !self.sess.source_map().is_multiline(prev_span.until(self.token.span)) {
+ return Ok(());
+ }
let mut snapshot = self.create_snapshot_for_diagnostic();
snapshot.bump();
match snapshot.parse_seq_to_before_end(
E0552,
"unrecognized representation hint"
)
+ .help("valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`")
.emit();
continue;
self.error(|| {
format!(
"ItemLocalIds not assigned densely in {}. \
- Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
+ Max ItemLocalId = {}, missing IDs = {:#?}; seens IDs = {:#?}",
self.hir_map.def_path(owner).to_string_no_crate_verbose(),
max,
missing_items,
}
}
+ #[instrument(level = "debug", skip(self))]
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
match &item.kind {
hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
}
}
+ #[instrument(level = "debug", skip(self))]
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
use self::hir::TraitItemKind::*;
match trait_item.kind {
}
}
+ #[instrument(level = "debug", skip(self))]
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
use self::hir::ImplItemKind::*;
match impl_item.kind {
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{
self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind,
- Term, Ty, TyCtxt, UintTy,
+ TermKind, Ty, TyCtxt, UintTy,
};
use rustc_span::def_id::DefId;
use rustc_span::symbol::sym;
let name = encode_ty_name(tcx, projection.item_def_id);
let _ = write!(s, "u{}{}", name.len(), &name);
s.push_str(&encode_substs(tcx, projection.substs, dict, options));
- match projection.term {
- Term::Ty(ty) => {
- s.push_str(&encode_ty(tcx, ty, dict, options));
- }
- Term::Const(c) => {
- s.push_str(&encode_const(tcx, c, dict, options));
- }
+ match projection.term.unpack() {
+ TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)),
+ TermKind::Const(c) => s.push_str(&encode_const(tcx, c, dict, options)),
}
}
ty::ExistentialPredicate::AutoTrait(def_id) => {
let name = cx.tcx.associated_item(projection.item_def_id).name;
cx.push("p");
cx.push_ident(name.as_str());
- cx = match projection.term {
- ty::Term::Ty(ty) => ty.print(cx),
- ty::Term::Const(c) => c.print(cx),
+ cx = match projection.term.unpack() {
+ ty::TermKind::Ty(ty) => ty.print(cx),
+ ty::TermKind::Const(c) => c.print(cx),
}?;
}
ty::ExistentialPredicate::AutoTrait(def_id) => {
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{Region, RegionVid, Term};
+use rustc_middle::ty::{Region, RegionVid};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
}
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
- if let Term::Ty(ty) = p.term().skip_binder() {
+ if let Some(ty) = p.term().skip_binder().ty() {
matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
} else {
false
)
.ok()
.flatten()
- .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
+ .unwrap_or_else(|| ty.super_fold_with(self).into())
};
// For cases like #95134 we would like to catch overflows early
// otherwise they slip away away and cause ICE.
}
ty::PredicateKind::Projection(t) => {
wf.compute_projection(t.projection_ty);
- wf.compute(match t.term {
- ty::Term::Ty(ty) => ty.into(),
- ty::Term::Const(c) => c.into(),
+ wf.compute(match t.term.unpack() {
+ ty::TermKind::Ty(ty) => ty.into(),
+ ty::TermKind::Const(c) => c.into(),
})
}
ty::PredicateKind::WellFormed(arg) => {
}
/// Pushes all the predicates needed to validate that `ty` is WF into `out`.
+ #[instrument(level = "debug", skip(self))]
fn compute(&mut self, arg: GenericArg<'tcx>) {
let mut walker = arg.walk();
let param_env = self.param_env;
}
};
+ debug!("wf bounds for ty={:?} ty.kind={:#?}", ty, ty.kind());
+
match *ty.kind() {
ty::Bool
| ty::Char
// `<T as Iterator>::Item = u32`
let assoc_item_def_id = projection_ty.skip_binder().item_def_id;
let def_kind = tcx.def_kind(assoc_item_def_id);
- match (def_kind, term) {
- (hir::def::DefKind::AssocTy, ty::Term::Ty(_))
- | (hir::def::DefKind::AssocConst, ty::Term::Const(_)) => (),
+ match (def_kind, term.unpack()) {
+ (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
+ | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (),
(_, _) => {
- let got = if let ty::Term::Ty(_) = term { "type" } else { "constant" };
+ let got = if let Some(_) = term.ty() { "type" } else { "constant" };
let expected = def_kind.descr(assoc_item_def_id);
tcx.sess
.struct_span_err(
let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be substituted with a
// `trait_object_dummy_self`, so check for that.
- let references_self = match pred.skip_binder().term {
- ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
- ty::Term::Const(c) => c.ty().walk().any(|arg| arg == dummy_self.into()),
+ let references_self = match pred.skip_binder().term.unpack() {
+ ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
+ ty::TermKind::Const(c) => {
+ c.ty().walk().any(|arg| arg == dummy_self.into())
+ }
};
// If the projection output contains `Self`, force the user to
result_ty
}
+ #[instrument(level = "debug", skip(self), ret)]
fn impl_trait_ty_to_ty(
&self,
def_id: DefId,
});
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
- let ty = tcx.mk_opaque(def_id, substs);
- debug!("impl_trait_ty_to_ty: {}", ty);
- ty
+ tcx.mk_opaque(def_id, substs)
}
pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{
- self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy, Term,
+ self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy,
ToPredicate, Ty, TypeVisitable,
};
use rustc_span::symbol::Ident;
opt_output_ty.zip(opt_output_assoc_item).map(|(output_ty, output_assoc_item)| {
ty::Binder::dummy(ty::PredicateKind::Projection(ProjectionPredicate {
projection_ty: ProjectionTy { substs, item_def_id: output_assoc_item.def_id },
- term: Term::Ty(output_ty),
+ term: output_ty.into(),
}))
.to_predicate(self.tcx)
});
/// Returns the predicates defined on `item_def_id` of the form
/// `X: Foo` where `X` is the type parameter `def_id`.
+#[instrument(level = "trace", skip(tcx))]
fn type_param_predicates(
tcx: TyCtxt<'_>,
(item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
assoc_name: Option<Ident>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
- debug!(?param_def_id);
+ trace!(?param_def_id);
ast_generics
.predicates
.iter()
.collect()
}
+ #[instrument(level = "trace", skip(self))]
fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
- debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name);
-
match b {
hir::GenericBound::Trait(poly_trait_ref, _) => {
let trait_ref = &poly_trait_ref.trait_ref;
/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
/// N.B., this does not include any implied/inferred constraints.
+#[instrument(level = "trace", skip(tcx), ret)]
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
use rustc_hir::*;
- debug!("explicit_predicates_of(def_id={:?})", def_id);
-
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let node = tcx.hir().get(hir_id);
+ has_own_self as u32
+ early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
+ trace!(?predicates);
+ trace!(?ast_generics);
+
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`).
for param in ast_generics.params {
Some((param.hir_id, ast_generics.predicates)),
param.span,
);
+ trace!(?bounds);
predicates.extend(bounds.predicates(tcx, param_ty));
+ trace!(?predicates);
}
GenericParamKind::Const { .. } => {
// Bounds on const parameters are currently not possible.
}
}
+ trace!(?predicates);
// Add in the bounds that appear in the where-clause.
for predicate in ast_generics.predicates {
match predicate {
);
}
- let result = ty::GenericPredicates {
+ ty::GenericPredicates {
parent: generics.parent,
predicates: tcx.arena.alloc_from_iter(predicates),
- };
- debug!("explicit_predicates_of(def_id={:?}) = {:?}", def_id, result);
- result
+ }
}
fn const_evaluatable_predicates_of<'tcx>(
/// impl trait it isn't possible to write a suitable predicate on the
/// containing function and for type-alias impl trait we don't have a backwards
/// compatibility issue.
+#[instrument(level = "trace", skip(tcx), ret)]
fn opaque_type_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
opaque_def_id: DefId,
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
// Opaque types are implicitly sized unless a `?Sized` bound is found
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+ debug!(?bounds);
+
tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
})
}
}
for projection in data.projection_bounds() {
- match projection.skip_binder().term {
- ty::Term::Ty(ty) => {
+ match projection.skip_binder().term.unpack() {
+ ty::TermKind::Ty(ty) => {
self.add_constraints_from_ty(current, ty, self.invariant);
}
- ty::Term::Const(c) => {
+ ty::TermKind::Const(c) => {
self.add_constraints_from_const(current, c, self.invariant)
}
}
/// the global stream.
///
/// However, if the actual I/O causes an error, this function does panic.
+///
+/// Writing to non-blocking stdout/stderr can cause an error, which will lead
+/// this function to panic.
fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
where
T: Write,
///
/// Panics if writing to `io::stdout()` fails.
///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
/// # Examples
///
/// ```
///
/// Panics if writing to [`io::stdout`] fails.
///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
/// [`io::stdout`]: crate::io::stdout
///
/// # Examples
///
/// Panics if writing to `io::stderr` fails.
///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
/// # Examples
///
/// ```
///
/// Panics if writing to `io::stderr` fails.
///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
/// # Examples
///
/// ```
mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
))?;
if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
- reparse_tag = attr_tag.ReparseTag;
+ attr.reparse_tag = attr_tag.ReparseTag;
}
}
Ok(attr)
```sh
${SDK_PATH}/tools/${ARCH}/pm \
+ -api-level $(${SDK_PATH}/tools/${ARCH}/ffx version -v | grep "api-level" | head -1 | awk -F ' ' '{print $2}') \
-o pkg/hello_fuchsia_manifest \
-m pkg/hello_fuchsia.manifest \
build \
}
fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
- match term {
- ty::Term::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)),
- ty::Term::Const(c) => Term::Constant(clean_middle_const(c, cx)),
+ match term.unpack() {
+ ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)),
+ ty::TermKind::Const(c) => Term::Constant(clean_middle_const(c, cx)),
}
}
text-align: center;
}
-#results > table {
- width: 100%;
- table-layout: fixed;
-}
-
.content > .example-wrap pre.line-numbers {
position: relative;
-webkit-user-select: none;
margin-left: 24px;
}
-.sub-variant > div > .item-info {
- margin-top: initial;
-}
-
.content .impl-items .docblock, .content .impl-items .item-info {
margin-bottom: .6em;
}
--- /dev/null
+// min-llvm-version: 15.0.0
+// ignore-debug: The debug assertions get in the way
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// There should be no calls to panic / len_mismatch_fail.
+
+#[no_mangle]
+pub fn test(a: &mut [u8], offset: usize, bytes: &[u8]) {
+ // CHECK-LABEL: @test(
+ // CHECK-NOT: call
+ // CHECK: call void @llvm.memcpy
+ // CHECK-NOT: call
+ // CHECK: }
+ if let Some(dst) = a.get_mut(offset..offset + bytes.len()) {
+ dst.copy_from_slice(bytes);
+ }
+}
--- /dev/null
+// revisions: rpass1 rpass2
+
+pub fn foo() {
+ bar();
+ baz::<()>();
+}
+
+fn bar()
+where
+ <() as Table>::AllColumns:,
+{
+}
+
+fn baz<W>()
+where
+ W: AsQuery,
+ <W as AsQuery>::Query:,
+{
+}
+
+trait AsQuery {
+ type Query;
+}
+
+trait UnimplementedTrait {}
+
+impl<T> AsQuery for T
+where
+ T: UnimplementedTrait,
+{
+ type Query = ();
+}
+
+struct Wrapper<Expr>(Expr);
+
+impl<Ret> AsQuery for Wrapper<Ret> {
+ type Query = ();
+}
+
+impl AsQuery for ()
+where
+ Wrapper<<() as Table>::AllColumns>: AsQuery,
+{
+ type Query = ();
+}
+
+trait Table {
+ type AllColumns;
+}
+
+#[cfg(rpass1)]
+impl Table for () {
+ type AllColumns = Checksum1;
+}
+#[cfg(rpass1)]
+struct Checksum1;
+
+#[cfg(rpass2)]
+impl Table for () {
+ type AllColumns = Checksum2;
+}
+#[cfg(rpass2)]
+struct Checksum2;
+
+fn main() {}
99
}
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
fn main() {
let mut x = [42, 43, 44];
+++ /dev/null
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11
- let mut _1: [u32; 3]; // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
- let mut _4: &mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- let mut _5: u32; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
- let mut _6: *mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
- let _7: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
- let mut _8: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- let mut _9: bool; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- scope 1 {
- debug x => _1; // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
- let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
- scope 2 {
- debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
- let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
- scope 3 {
- debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
- scope 4 {
- }
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
- _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29
- StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
- _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18
- StorageLive(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
- StorageLive(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- _4 = &mut _2; // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- _3 = &raw mut (*_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- StorageDead(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32
- StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
- StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
- _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
- _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27
- // mir::Constant
- // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
- // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27
- StorageLive(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
- _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
- _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- }
-
- bb2: {
- _1[_7] = move _5; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29
- StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29
- StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30
- _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2
- StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
- StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
- StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
- return; // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2
- }
-}
+++ /dev/null
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11
- let mut _1: [u32; 3]; // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
- let mut _4: &mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- let mut _5: u32; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
- let mut _6: *mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
- let _7: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
- let mut _8: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- let mut _9: bool; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- scope 1 {
- debug x => _1; // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
- let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
- scope 2 {
- debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
- let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
- scope 3 {
- debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
- scope 4 {
- }
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
- _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29
- StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
- _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18
- StorageLive(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
- StorageLive(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- _4 = &mut _2; // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- _3 = &raw mut (*_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- StorageDead(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32
- StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
- StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
- _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
- _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27
- // mir::Constant
- // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
- // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27
- StorageLive(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
- _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
- _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- }
-
- bb2: {
- _1[_7] = move _5; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29
- StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29
- StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30
- _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2
- StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
- StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
- StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
- return; // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2
- }
-}
--- /dev/null
+// MIR for `main` after SimplifyCfg-elaborate-drops
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11
+ let mut _1: [u32; 3]; // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
+ let mut _4: &mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
+ let mut _5: u32; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
+ let mut _6: *mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
+ let _7: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
+ let mut _8: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+ let mut _9: bool; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+ scope 1 {
+ debug x => _1; // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
+ let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
+ scope 2 {
+ debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
+ let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
+ scope 3 {
+ debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
+ scope 4 {
+ }
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
+ _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29
+ StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
+ _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18
+ StorageLive(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
+ StorageLive(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
+ _4 = &mut _2; // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
+ _3 = &raw mut (*_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
+ StorageDead(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32
+ StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
+ StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
+ _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
+ _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27
+ // mir::Constant
+ // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
+ // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27
+ StorageLive(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
+ _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
+ _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+ _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+ assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+ }
+
+ bb2: {
+ _1[_7] = move _5; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29
+ StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29
+ StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30
+ _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2
+ StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
+ StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
+ StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2
+ }
+}
// ignore-endian-big
// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -Z mir-opt-level=4
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
#![feature(box_syntax)]
// EMIT_MIR inline_into_box_place.main.Inline.diff
fn main() {
+++ /dev/null
-- // MIR for `main` before Inline
-+ // MIR for `main` after Inline
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11
- let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
- let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
- let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
- scope 1 {
- debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
- }
- scope 2 {
- }
-+ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
- _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- // mir::Constant
- // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
- // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-- (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ StorageLive(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ _8 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- // mir::Constant
-- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
-- // + user_ty: UserType(1)
-- // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
-- }
--
-- bb2: {
-+ // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ // + user_ty: UserType(0)
-+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
- _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
- _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2
-- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-+ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
- }
-
-- bb3: {
-+ bb2: {
- StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
- return; // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2
- }
-
-- bb4 (cleanup): {
-+ bb3 (cleanup): {
- resume; // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2
-- }
--
-- bb5 (cleanup): {
-- _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
-- // mir::Constant
-- // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
-- // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
- }
- }
-
+++ /dev/null
-- // MIR for `main` before Inline
-+ // MIR for `main` after Inline
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11
- let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
- let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
- let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
- scope 1 {
- debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
- }
- scope 2 {
- }
-+ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
- _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- // mir::Constant
- // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
- // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-- (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ StorageLive(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ _8 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- // mir::Constant
-- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
-- // + user_ty: UserType(1)
-- // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
-- }
--
-- bb2: {
-+ // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ // + user_ty: UserType(0)
-+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
- _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
- _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2
-- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-+ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
- }
-
-- bb3: {
-+ bb2: {
- StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
- return; // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2
- }
-
-- bb4 (cleanup): {
-+ bb3 (cleanup): {
- resume; // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2
-- }
--
-- bb5 (cleanup): {
-- _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
-- // mir::Constant
-- // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
-- // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
- }
- }
-
--- /dev/null
+- // MIR for `main` before Inline
++ // MIR for `main` after Inline
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11
+ let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
+ let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
+ let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
++ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
+ scope 1 {
+ debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
+ }
+ scope 2 {
+ }
++ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
++ let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
+ _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ // mir::Constant
+ // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
+- (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ StorageLive(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ _8 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ // mir::Constant
+- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
+- // + user_ty: UserType(1)
+- // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
+- }
+-
+- bb2: {
++ // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ // + user_ty: UserType(0)
++ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
++ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageDead(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
+ _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
+ _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2
+- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
+ }
+
+- bb3: {
++ bb2: {
+ StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2
+ }
+
+- bb4 (cleanup): {
++ bb3 (cleanup): {
+ resume; // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2
+- }
+-
+- bb5 (cleanup): {
+- _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
+- // mir::Constant
+- // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
+- // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
+ }
+ }
+
fn get(&self) -> [u8; 2];
}
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
impl Foo for [u8; 1+1] {
fn get(&self) -> [u8; 2] {
b: Never
}
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR issue_72181.foo.mir_map.0.mir
fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 }
// EMIT_MIR issue_72181.bar.mir_map.0.mir
fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x }
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR issue_72181.main.mir_map.0.mir
fn main() {
let _ = mem::size_of::<Foo>();
assert_eq!(split, 1);
}
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff
+++ /dev/null
-// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts
-
-<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = {
- let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-
- bb0: {
- _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- }
-
- bb1: {
- _0 = move (_1.0: usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- return; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- }
-}
+++ /dev/null
-// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts
-
-<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = {
- let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-
- bb0: {
- _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- }
-
- bb1: {
- _0 = move (_1.0: usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- return; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- }
-}
--- /dev/null
+// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts
+
+<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = {
+ let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+ let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+
+ bb0: {
+ _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+ assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+ }
+
+ bb1: {
+ _0 = move (_1.0: usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+ return; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+ }
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+ }
+}
+++ /dev/null
-// MIR for `bar` 0 mir_map
-
-fn bar(_1: [(Never, u32); 1]) -> u32 {
- let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43
- let _2: u32; // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
- scope 1 {
- debug x => _2; // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
- _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
- _0 = _2; // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47
- StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
- return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
- }
-}
+++ /dev/null
-// MIR for `bar` 0 mir_map
-
-fn bar(_1: [(Never, u32); 1]) -> u32 {
- let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43
- let _2: u32; // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
- scope 1 {
- debug x => _2; // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
- _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
- _0 = _2; // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47
- StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
- return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
- }
-}
--- /dev/null
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: [(Never, u32); 1]) -> u32 {
+ let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43
+ let _2: u32; // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
+ scope 1 {
+ debug x => _2; // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
+ _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
+ _0 = _2; // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47
+ StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
+ return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
+ }
+}
+++ /dev/null
-// MIR for `foo` 0 mir_map
-
-fn foo(_1: [(Never, u32); 1]) -> u32 {
- debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10
- let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37
- let _2: usize; // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
- let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
- _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
- _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- }
-
- bb1: {
- _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47
- StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
- return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49
- }
-}
+++ /dev/null
-// MIR for `foo` 0 mir_map
-
-fn foo(_1: [(Never, u32); 1]) -> u32 {
- debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10
- let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37
- let _2: usize; // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
- let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
- _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
- _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- }
-
- bb1: {
- _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47
- StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
- return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49
- }
-}
--- /dev/null
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: [(Never, u32); 1]) -> u32 {
+ debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10
+ let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37
+ let _2: usize; // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
+ let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+ let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
+ _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
+ _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+ _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+ assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+ }
+
+ bb1: {
+ _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47
+ StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
+ return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
+ }
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49
+ }
+}
+++ /dev/null
-// MIR for `main` 0 mir_map
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11
- let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
- let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27
- let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42
- let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30
- let _6: usize; // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25
- let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
- let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
- scope 1 {
- let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
- scope 2 {
- debug f => _2; // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10
- scope 3 {
- }
- scope 4 {
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
- _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
- // mir::Constant
- // + span: $DIR/issue-72181.rs:24:13: 24:32
- // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35
- StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
- StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
- _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
- StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
- _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
- _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43
- StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
- StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
- FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
- StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30
- StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
- _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
- _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
- _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
- }
-
- bb2: {
- _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28
- StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
- StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
- _0 = const (); // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2
- StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2
- return; // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2
- }
-
- bb3 (cleanup): {
- resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2
- }
-}
+++ /dev/null
-// MIR for `main` 0 mir_map
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11
- let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
- let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27
- let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42
- let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30
- let _6: usize; // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25
- let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
- let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
- scope 1 {
- let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
- scope 2 {
- debug f => _2; // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10
- scope 3 {
- }
- scope 4 {
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
- _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
- // mir::Constant
- // + span: $DIR/issue-72181.rs:24:13: 24:32
- // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35
- StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
- StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
- _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
- StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
- _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
- _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43
- StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
- StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
- FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
- StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30
- StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
- _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
- _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
- _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
- }
-
- bb2: {
- _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28
- StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
- StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
- _0 = const (); // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2
- StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2
- return; // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2
- }
-
- bb3 (cleanup): {
- resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2
- }
-}
--- /dev/null
+// MIR for `main` 0 mir_map
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11
+ let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
+ let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27
+ let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42
+ let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30
+ let _6: usize; // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25
+ let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
+ let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
+ scope 1 {
+ let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
+ scope 2 {
+ debug f => _2; // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10
+ scope 3 {
+ }
+ scope 4 {
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
+ _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
+ // mir::Constant
+ // + span: $DIR/issue-72181.rs:24:13: 24:32
+ // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35
+ StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
+ StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
+ _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
+ StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
+ _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
+ _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43
+ StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
+ StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
+ FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
+ StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30
+ StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
+ _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
+ _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
+ _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
+ }
+
+ bb2: {
+ _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28
+ StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
+ StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
+ _0 = const (); // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2
+ StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2
+ }
+
+ bb3 (cleanup): {
+ resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2
+ }
+}
+++ /dev/null
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
- let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- let mut _3: isize; // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16
- let _4: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- let mut _5: !; // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
- let mut _7: i32; // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27
- let _8: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _9: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _10: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _11: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _12: i32; // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24
- let mut _15: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _18: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _19: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _21: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _23: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _24: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _25: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _27: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 1 {
- debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
- let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
- scope 3 {
- debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
- let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _28: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 4 {
- debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug right_val => _14; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 5 {
- debug kind => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
- }
- }
- }
- scope 2 {
- debug v => _4; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- _3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- goto -> bb3; // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30
- }
-
- bb1: {
- nop; // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
- StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
- return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- }
-
- bb3: {
- StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _1 = _4; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_4); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
- StorageLive(_6); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
- StorageLive(_7); // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
- _7 = _1; // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
- Deinit(_6); // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
- ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
- discriminant(_6) = 1; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
- StorageDead(_7); // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28
- StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _10 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _28 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
- _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _13 = (_9.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _14 = (_9.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _17 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _18 = const 1_i32; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- switchInt(move _15) -> [false: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb4: {
- StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- discriminant(_20) = 0; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_21); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
- StorageLive(_23); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_24); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _24 = _13; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _23 = _24; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_25); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_26); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _26 = _14; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _25 = _26; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- discriminant(_27) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
- }
-
- bb5: {
- nop; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- nop; // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2
- StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
- return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
- }
- }
-
+++ /dev/null
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
- let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- let mut _3: isize; // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16
- let _4: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- let mut _5: !; // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
- let mut _7: i32; // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27
- let _8: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _9: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _10: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _11: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _12: i32; // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24
- let mut _15: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _18: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _19: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _21: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _23: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _24: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _25: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _27: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 1 {
- debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
- let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
- scope 3 {
- debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
- let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _28: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 4 {
- debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug right_val => _14; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 5 {
- debug kind => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
- }
- }
- }
- scope 2 {
- debug v => _4; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- _3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- goto -> bb3; // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30
- }
-
- bb1: {
- nop; // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
- StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
- return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- }
-
- bb3: {
- StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _1 = _4; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_4); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
- StorageLive(_6); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
- StorageLive(_7); // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
- _7 = _1; // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
- Deinit(_6); // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
- ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
- discriminant(_6) = 1; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
- StorageDead(_7); // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28
- StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _10 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _28 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
- _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _13 = (_9.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _14 = (_9.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _17 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _18 = const 1_i32; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- switchInt(move _15) -> [false: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb4: {
- StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- discriminant(_20) = 0; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_21); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
- StorageLive(_23); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_24); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _24 = _13; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _23 = _24; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_25); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_26); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _26 = _14; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _25 = _26; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- Deinit(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- discriminant(_27) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
- }
-
- bb5: {
- nop; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- nop; // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2
- StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
- return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
- }
- }
-
--- /dev/null
+- // MIR for `main` before SimplifyArmIdentity
++ // MIR for `main` after SimplifyArmIdentity
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
+ let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
+ let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+ let mut _3: isize; // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16
+ let _4: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
+ let mut _5: !; // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
+ let mut _7: i32; // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27
+ let _8: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _9: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _10: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _11: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _12: i32; // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24
+ let mut _15: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _18: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _19: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _21: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _23: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _24: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _25: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _27: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 1 {
+ debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
+ let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
+ scope 3 {
+ debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
+ let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _28: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 4 {
+ debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug right_val => _14; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 5 {
+ debug kind => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+ }
+ }
+ }
+ scope 2 {
+ debug v => _4; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
+ StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+ Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+ ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+ discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+ _3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+ goto -> bb3; // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30
+ }
+
+ bb1: {
+ nop; // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
+ StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
+ StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
+ return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
+ }
+
+ bb2: {
+ unreachable; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+ }
+
+ bb3: {
+ StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
+ _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
+ _1 = _4; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
+ StorageDead(_4); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
+ StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
+ StorageLive(_6); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
+ StorageLive(_7); // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
+ _7 = _1; // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
+ Deinit(_6); // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
+ ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
+ discriminant(_6) = 1; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
+ StorageDead(_7); // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28
+ StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _10 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _28 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
+ _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ Deinit(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _13 = (_9.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _14 = (_9.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _17 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _18 = const 1_i32; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ switchInt(move _15) -> [false: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb4: {
+ StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ Deinit(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ discriminant(_20) = 0; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_21); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
+ StorageLive(_23); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_24); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _24 = _13; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _23 = _24; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_25); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_26); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _26 = _14; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _25 = _26; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ Deinit(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ discriminant(_27) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
+ }
+
+ bb5: {
+ nop; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ nop; // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2
+ StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
+ StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
+ return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
+ }
+ }
+
--- /dev/null
+- // MIR for `assume` before LowerIntrinsics
++ // MIR for `assume` after LowerIntrinsics
+
+ fn assume() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17
+ let _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+ scope 1 {
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+- _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+- // mir::Constant
+- // + span: $DIR/lower_intrinsics.rs:72:9: 72:32
+- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
++ assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+ }
+
+ bb1: {
+ StorageDead(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:38: +2:39
+ _0 = const (); // scope 1 at $DIR/lower_intrinsics.rs:+1:5: +3:6
+ return; // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
+ }
+ }
+
--- /dev/null
+- // MIR for `f_copy_nonoverlapping` before LowerIntrinsics
++ // MIR for `f_copy_nonoverlapping` after LowerIntrinsics
+
+ fn f_copy_nonoverlapping() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:32: +0:32
+ let _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+ let _3: (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+ let mut _4: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+ let mut _5: *const (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+ let mut _6: *const (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+ let _7: &(); // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+ let mut _8: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+ let mut _9: *mut (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+ let mut _10: *mut (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+ let mut _11: &mut (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+ scope 1 {
+ debug src => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+ let mut _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+ scope 2 {
+ debug dst => _2; // in scope 2 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+ scope 3 {
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+ Deinit(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:15: +1:17
+ StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+ Deinit(_2); // scope 1 at $DIR/lower_intrinsics.rs:+2:19: +2:21
+ StorageLive(_3); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+ StorageLive(_4); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+ StorageLive(_5); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+ StorageLive(_6); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+ StorageLive(_7); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+ _7 = &_1; // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+ _6 = &raw const (*_7); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+ _5 = _6; // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+ _4 = move _5 as *const i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+ StorageDead(_5); // scope 3 at $DIR/lower_intrinsics.rs:+4:58: +4:59
+ StorageLive(_8); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+ StorageLive(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+ StorageLive(_10); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+ StorageLive(_11); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+ _11 = &mut _2; // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+ _10 = &raw mut (*_11); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+ _9 = _10; // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+ _8 = move _9 as *mut i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+ StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91
+- _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+- // mir::Constant
+- // + span: $DIR/lower_intrinsics.rs:65:9: 65:28
+- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) }
++ copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
++ goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+ }
+
+ bb1: {
+ StorageDead(_8); // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95
+ StorageDead(_4); // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95
+ StorageDead(_11); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+ StorageDead(_10); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+ StorageDead(_7); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+ StorageDead(_6); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+ StorageDead(_3); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+ _0 = const (); // scope 3 at $DIR/lower_intrinsics.rs:+3:5: +5:6
+ StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+6:1: +6:2
+ StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/lower_intrinsics.rs:+6:2: +6:2
+ }
+ }
+
// unit-test: LowerIntrinsics
// ignore-wasm32 compiled with panic=abort by default
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, intrinsics)]
#![crate_type = "lib"]
// EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff
core::intrinsics::discriminant_value(&());
core::intrinsics::discriminant_value(&E::B);
}
+
+extern "rust-intrinsic" {
+ // Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function
+ fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+}
+
+// EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
+pub fn f_copy_nonoverlapping() {
+ let src = ();
+ let mut dst = ();
+ unsafe {
+ copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
+ }
+}
+
+// EMIT_MIR lower_intrinsics.assume.LowerIntrinsics.diff
+pub fn assume() {
+ unsafe {
+ std::intrinsics::assume(true);
+ }
+}
+++ /dev/null
-- // MIR for `bar` before MatchBranchSimplification
-+ // MIR for `bar` after MatchBranchSimplification
-
- fn bar(_1: i32) -> (bool, bool, bool, bool) {
- debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9
- let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43
- let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
- let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
- let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
- let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
- let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
- let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-+ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
- scope 1 {
- debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
- let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
- scope 2 {
- debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
- let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
- scope 3 {
- debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
- let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
- scope 4 {
- debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
- }
- }
- }
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
- StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
- StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
- StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
- StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
-- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-- }
--
-- bb1: {
-- _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21
-- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
-- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
-- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
-- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
-- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
-- }
--
-- bb2: {
-- _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
-- _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
-+ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
-+ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
-- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
-- }
--
-- bb3: {
-+ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
- StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7
- StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
- _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
- StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
- _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
- StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
- _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
- StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
- _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
- Deinit(_0); // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
- StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
- StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
- StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
- StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
- StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
- StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
- return; // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2
- }
- }
-
+++ /dev/null
-- // MIR for `bar` before MatchBranchSimplification
-+ // MIR for `bar` after MatchBranchSimplification
-
- fn bar(_1: i32) -> (bool, bool, bool, bool) {
- debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9
- let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43
- let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
- let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
- let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
- let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
- let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
- let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-+ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
- scope 1 {
- debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
- let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
- scope 2 {
- debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
- let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
- scope 3 {
- debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
- let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
- scope 4 {
- debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
- }
- }
- }
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
- StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
- StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
- StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
- StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
-- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-- }
--
-- bb1: {
-- _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21
-- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
-- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
-- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
-- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
-- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
-- }
--
-- bb2: {
-- _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
-- _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
-+ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
-+ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
-- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
-- }
--
-- bb3: {
-+ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
- StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7
- StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
- _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
- StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
- _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
- StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
- _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
- StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
- _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
- Deinit(_0); // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
- StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
- StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
- StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
- StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
- StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
- StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
- StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
- return; // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2
- }
- }
-
--- /dev/null
+- // MIR for `bar` before MatchBranchSimplification
++ // MIR for `bar` after MatchBranchSimplification
+
+ fn bar(_1: i32) -> (bool, bool, bool, bool) {
+ debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9
+ let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43
+ let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
+ let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
+ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
+ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
+ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
+ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
++ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
+ scope 1 {
+ debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
+ let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
+ scope 2 {
+ debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
+ let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
+ scope 3 {
+ debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
+ let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
+ scope 4 {
+ debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
+ }
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
+ StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
+ StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
+ StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
+ StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
+- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
+- }
+-
+- bb1: {
+- _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21
+- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
+- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
+- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
+- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
+- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
+- }
+-
+- bb2: {
+- _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
+- _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
++ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
++ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
++ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
++ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
+ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
+ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
+ Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
+- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
+- }
+-
+- bb3: {
++ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
+ StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7
+ StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
+ _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
+ StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
+ _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
+ StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
+ _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
+ StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
+ _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
+ Deinit(_0); // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+ (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+ (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+ (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+ (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+ StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
+ StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
+ StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
+ StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
+ StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
+ StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
+ StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
+ StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
+ return; // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `foo` before MatchBranchSimplification
-+ // MIR for `foo` after MatchBranchSimplification
-
- fn foo(_1: Option<()>) -> () {
- debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
- let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
- let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
-+ let mut _4: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-
- bb0: {
- StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
-- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ _4 = move _3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb1: {
-- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- }
--
-- bb2: {
-- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- }
--
-- bb3: {
-- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- }
--
-- bb4: {
- Deinit(_0); // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
-- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
- }
-
-- bb5: {
-+ bb2: {
- _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6
-- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
- }
-
-- bb6: {
-+ bb3: {
- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6
- return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
- }
- }
-
+++ /dev/null
-- // MIR for `foo` before MatchBranchSimplification
-+ // MIR for `foo` after MatchBranchSimplification
-
- fn foo(_1: Option<()>) -> () {
- debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
- let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
- let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
-+ let mut _4: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-
- bb0: {
- StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
-- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ _4 = move _3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb1: {
-- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- }
--
-- bb2: {
-- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- }
--
-- bb3: {
-- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-- }
--
-- bb4: {
- Deinit(_0); // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
-- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
- }
-
-- bb5: {
-+ bb2: {
- _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6
-- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
- }
-
-- bb6: {
-+ bb3: {
- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6
- return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
- }
- }
-
--- /dev/null
+- // MIR for `foo` before MatchBranchSimplification
++ // MIR for `foo` after MatchBranchSimplification
+
+ fn foo(_1: Option<()>) -> () {
+ debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
+ let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
+ let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
++ let mut _4: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
+- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ _4 = move _3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb1: {
+- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+- }
+-
+- bb2: {
+- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+- }
+-
+- bb3: {
+- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+- }
+-
+- bb4: {
+ Deinit(_0); // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
+ }
+
+- bb5: {
++ bb2: {
+ _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
+ }
+
+- bb6: {
++ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6
+ return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `match_nested_if` before MatchBranchSimplification
-+ // MIR for `match_nested_if` after MatchBranchSimplification
-
- fn match_nested_if() -> bool {
- let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29
- let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
- let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
- let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- scope 1 {
- debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
- Deinit(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
- StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
- StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- _6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-- }
--
-- bb1: {
-- _5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35
-- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-- }
--
-- bb2: {
-- _5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
-- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-- }
--
-- bb3: {
-+ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ _7 = move _6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
-+ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
-- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-- }
--
-- bb4: {
-- _4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59
-- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-- }
--
-- bb5: {
-- _4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
-- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-- }
--
-- bb6: {
-+ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+ _8 = move _5; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
-+ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76
-- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-- }
--
-- bb7: {
-- _3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17
-- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-- }
--
-- bb8: {
-- _3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
-- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-- }
--
-- bb9: {
-- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-- }
--
-- bb10: {
-+ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+ _9 = move _4; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
-+ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-+ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
-- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
-- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
-- }
--
-- bb11: {
-- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
-- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
-- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-- }
--
-- bb12: {
-+ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-+ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7
- _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8
- StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2
- return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2
- }
- }
-
+++ /dev/null
-- // MIR for `match_nested_if` before MatchBranchSimplification
-+ // MIR for `match_nested_if` after MatchBranchSimplification
-
- fn match_nested_if() -> bool {
- let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29
- let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
- let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
- let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- scope 1 {
- debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
- StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
- Deinit(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
- StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
- StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- _6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-- }
--
-- bb1: {
-- _5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35
-- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-- }
--
-- bb2: {
-- _5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
-- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-- }
--
-- bb3: {
-+ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ _7 = move _6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
-+ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
- StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
-- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-- }
--
-- bb4: {
-- _4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59
-- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-- }
--
-- bb5: {
-- _4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
-- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-- }
--
-- bb6: {
-+ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+ _8 = move _5; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
-+ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
- StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76
-- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-- }
--
-- bb7: {
-- _3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17
-- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-- }
--
-- bb8: {
-- _3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
-- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-- }
--
-- bb9: {
-- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-- }
--
-- bb10: {
-+ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+ _9 = move _4; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
-+ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-+ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
-- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
-- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
-- }
--
-- bb11: {
-- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
-- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
-- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-- }
--
-- bb12: {
-+ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-+ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7
- _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8
- StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2
- return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2
- }
- }
-
--- /dev/null
+- // MIR for `match_nested_if` before MatchBranchSimplification
++ // MIR for `match_nested_if` after MatchBranchSimplification
+
+ fn match_nested_if() -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29
+ let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
+ let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+ let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+ let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ scope 1 {
+ debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
+ StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+ Deinit(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+ StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+ StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ _6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+- }
+-
+- bb1: {
+- _5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35
+- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+- }
+-
+- bb2: {
+- _5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
+- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+- }
+-
+- bb3: {
++ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ _7 = move _6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
++ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+ StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
+- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+- }
+-
+- bb4: {
+- _4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+- }
+-
+- bb5: {
+- _4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
+- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+- }
+-
+- bb6: {
++ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++ _8 = move _5; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
++ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+ StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76
+- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+- }
+-
+- bb7: {
+- _3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17
+- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+- }
+-
+- bb8: {
+- _3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
+- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+- }
+-
+- bb9: {
+- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+- }
+-
+- bb10: {
++ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ _9 = move _4; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
++ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
++ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+- }
+-
+- bb11: {
+- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+- }
+-
+- bb12: {
++ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
++ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+ StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7
+ _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8
+ StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2
+ return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2
+ }
+ }
+
// unit-test: MatchBranchSimplification
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
+++ /dev/null
-- // MIR for `exhaustive_match` before MatchBranchSimplification
-+ // MIR for `exhaustive_match` after MatchBranchSimplification
-
- fn exhaustive_match(_1: E) -> u8 {
- debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26
- let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36
- let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-
- bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
- }
-
- bb1: {
- _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
- goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
- }
-
- bb3: {
- _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
- goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
- }
-
- bb4: {
- return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
- }
- }
-
+++ /dev/null
-- // MIR for `exhaustive_match` before MatchBranchSimplification
-+ // MIR for `exhaustive_match` after MatchBranchSimplification
-
- fn exhaustive_match(_1: E) -> u8 {
- debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26
- let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36
- let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-
- bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
- }
-
- bb1: {
- _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
- goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
- }
-
- bb3: {
- _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
- goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
- }
-
- bb4: {
- return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
- }
- }
-
--- /dev/null
+- // MIR for `exhaustive_match` before MatchBranchSimplification
++ // MIR for `exhaustive_match` after MatchBranchSimplification
+
+ fn exhaustive_match(_1: E) -> u8 {
+ debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26
+ let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36
+ let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
+
+ bb0: {
+ _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
+ switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
+ }
+
+ bb1: {
+ _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
+ goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
+ }
+
+ bb2: {
+ unreachable; // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
+ }
+
+ bb3: {
+ _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
+ goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
+ }
+
+ bb4: {
+ return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
+ }
+ }
+
+++ /dev/null
-- // MIR for `exhaustive_match_i8` before MatchBranchSimplification
-+ // MIR for `exhaustive_match_i8` after MatchBranchSimplification
-
- fn exhaustive_match_i8(_1: E) -> i8 {
- debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29
- let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39
- let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-
- bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
- }
-
- bb1: {
- _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
- goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
- }
-
- bb3: {
- _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
- goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
- }
-
- bb4: {
- return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
- }
- }
-
+++ /dev/null
-- // MIR for `exhaustive_match_i8` before MatchBranchSimplification
-+ // MIR for `exhaustive_match_i8` after MatchBranchSimplification
-
- fn exhaustive_match_i8(_1: E) -> i8 {
- debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29
- let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39
- let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-
- bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
- }
-
- bb1: {
- _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
- goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
- }
-
- bb3: {
- _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
- goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
- }
-
- bb4: {
- return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
- }
- }
-
--- /dev/null
+- // MIR for `exhaustive_match_i8` before MatchBranchSimplification
++ // MIR for `exhaustive_match_i8` after MatchBranchSimplification
+
+ fn exhaustive_match_i8(_1: E) -> i8 {
+ debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29
+ let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39
+ let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
+
+ bb0: {
+ _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
+ switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
+ }
+
+ bb1: {
+ _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
+ goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
+ }
+
+ bb2: {
+ unreachable; // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
+ }
+
+ bb3: {
+ _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
+ goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
+ }
+
+ bb4: {
+ return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
+ }
+ }
+
// unit-test: MatchBranchSimplification
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff
// EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
// ignore-wasm32-bare compiled with panic=abort by default
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
fn main() {
let mut x = Packed(Aligned(Droppy(0)));
+++ /dev/null
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11
- let mut _1: Packed; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
- let mut _2: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- let mut _3: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- let mut _4: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- let mut _5: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- let mut _6: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- scope 1 {
- debug x => _1; // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
- StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- Deinit(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- (_3.0: usize) = const 0_usize; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- Deinit(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- (_2.0: Droppy) = move _3; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
- Deinit(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
- (_1.0: Aligned) = move _2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
- StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
- StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- Deinit(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- (_5.0: usize) = const 0_usize; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- Deinit(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- (_4.0: Droppy) = move _5; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
- StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- }
-
- bb1: {
- StorageDead(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
- return; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2
- }
-
- bb3 (cleanup): {
- (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- drop(_1) -> bb2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
- }
-
- bb4: {
- StorageDead(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
- _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2
- drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
- }
-}
+++ /dev/null
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11
- let mut _1: Packed; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
- let mut _2: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- let mut _3: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- let mut _4: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- let mut _5: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- let mut _6: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- scope 1 {
- debug x => _1; // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
- StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- Deinit(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- (_3.0: usize) = const 0_usize; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- Deinit(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- (_2.0: Droppy) = move _3; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
- Deinit(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
- (_1.0: Aligned) = move _2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
- StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
- StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- Deinit(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- (_5.0: usize) = const 0_usize; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- Deinit(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- (_4.0: Droppy) = move _5; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
- StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- }
-
- bb1: {
- StorageDead(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
- return; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2
- }
-
- bb3 (cleanup): {
- (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- drop(_1) -> bb2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
- }
-
- bb4: {
- StorageDead(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
- _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2
- drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
- }
-}
--- /dev/null
+// MIR for `main` after SimplifyCfg-elaborate-drops
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11
+ let mut _1: Packed; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
+ let mut _2: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+ let mut _3: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
+ let mut _4: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+ let mut _5: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
+ let mut _6: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+ scope 1 {
+ debug x => _1; // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
+ StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+ StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
+ Deinit(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
+ (_3.0: usize) = const 0_usize; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
+ Deinit(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+ (_2.0: Droppy) = move _3; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+ StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
+ Deinit(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
+ (_1.0: Aligned) = move _2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
+ StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
+ StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+ StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
+ Deinit(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
+ (_5.0: usize) = const 0_usize; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
+ Deinit(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+ (_4.0: Droppy) = move _5; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+ StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
+ StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+ _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+ drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+ }
+
+ bb1: {
+ StorageDead(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2
+ }
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2
+ }
+
+ bb3 (cleanup): {
+ (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+ drop(_1) -> bb2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
+ }
+
+ bb4: {
+ StorageDead(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+ (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+ StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
+ _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2
+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
+ }
+}
+++ /dev/null
-- // MIR for `identity` before ConstProp
-+ // MIR for `identity` after ConstProp
-
- fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
- debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
- let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
- let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
- let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- let _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- let mut _8: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- scope 1 {
- debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
- scope 2 {
- scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
- debug residual => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- let _16: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _17: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _18: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- scope 9 {
- debug e => _16; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
- debug t => _18; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- }
- }
- }
- }
- }
- scope 3 {
- debug val => _9; // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
- scope 4 {
- }
- }
- scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
- debug self => _4; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _10: isize; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let _11: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _12: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let _13: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _14: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _15: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- scope 6 {
- debug v => _11; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- }
- scope 7 {
- debug e => _13; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- }
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
- _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
- _10 = discriminant(_4); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- }
-
- bb1: {
- StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- _2 = _9; // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
- StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
- ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
- discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
- StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
- StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
- return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- }
-
- bb3: {
- StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
- _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageLive(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- _16 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- _18 = move _16; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- _17 = move _18; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
- StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
- return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
- }
-
- bb4: {
- StorageLive(_13); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- _13 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_15); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- _15 = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_14) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_15); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_3); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_3) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_13); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+ _5 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+ switchInt(const 1_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- }
-
- bb5: {
- unreachable; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- }
-
- bb6: {
- StorageLive(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- _11 = move ((_4 as Ok).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- _12 = move _11; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_3); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_3) = 0; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+ _5 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+ switchInt(const 0_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- }
- }
-
+++ /dev/null
-// MIR for `identity` after PreCodegen
-
-fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
- debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
- let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
- let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
- let _5: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- let mut _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- scope 1 {
- debug residual => _5; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
- scope 2 {
- scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
- debug residual => _6; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- let _14: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _15: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _16: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- scope 9 {
- debug e => _14; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
- debug t => _16; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- }
- }
- }
- }
- }
- scope 3 {
- debug val => _7; // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
- scope 4 {
- }
- }
- scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
- debug self => _4; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _8: isize; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let _9: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _10: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let _11: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _12: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- let mut _13: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- scope 6 {
- debug v => _9; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- }
- scope 7 {
- debug e => _11; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- }
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
- _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
- _8 = discriminant(_4); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- switchInt(move _8) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- }
-
- bb1: {
- StorageLive(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- _11 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_13); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- _13 = move _11; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_12 as Err).0: i32) = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_12) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_13); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_3); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _12; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_3) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageLive(_5); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- _5 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageLive(_6); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
- _6 = _5; // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageLive(_14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- _14 = move ((_6 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- _16 = move _14; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- _15 = move _16; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- StorageDead(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_0 as Err).0: i32) = move _15; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_6); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_5); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
- StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
- return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
- }
-
- bb2: {
- unreachable; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- }
-
- bb3: {
- StorageLive(_9); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- _9 = move ((_4 as Ok).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageLive(_10); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- _10 = move _9; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_3); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_3 as Continue).0: i32) = move _10; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_3) = 0; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_10); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_9); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- _7 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
- _2 = _7; // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
- StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
- ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
- discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
- StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
- StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
- return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
- }
-}
+++ /dev/null
-- // MIR for `too_complex` before ConstProp
-+ // MIR for `too_complex` after ConstProp
-
- fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
- debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
- let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
- let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
- let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
- let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
- let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
- let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
- let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:42: +8:43
- let mut _8: isize; // in scope 0 at $DIR/separate_const_switch.rs:+11:9: +11:33
- let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
- let mut _10: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
- let _11: usize; // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
- scope 1 {
- debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
- }
- scope 2 {
- debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
- }
- scope 3 {
- debug v => _9; // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
- }
- scope 4 {
- debug r => _11; // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
- _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
- switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
- }
-
- bb1: {
- StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
- _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
- StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
- _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
- Deinit(_2); // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
- ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
- discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
- StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44
- StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
-- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-- switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+ _8 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+ switchInt(const 1_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
- }
-
- bb3: {
- StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
- _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
- StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
- _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
- Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
- ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
- discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
- StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
- StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
-- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-- switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+ _8 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+ switchInt(const 0_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
- }
-
- bb4: {
- StorageLive(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
- _11 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
- Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
- discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
- StorageDead(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
- goto -> bb7; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
- }
-
- bb5: {
- unreachable; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
- }
-
- bb6: {
- StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
- _9 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
- StorageLive(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
- _10 = _9; // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
- Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
- ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
- discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
- StorageDead(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
- StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
- goto -> bb7; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
- }
-
- bb7: {
- StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
- return; // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
- }
- }
-
+++ /dev/null
-// MIR for `too_complex` after PreCodegen
-
-fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
- debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
- let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
- let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
- let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
- let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
- let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
- let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
- let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
- let mut _8: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
- let _9: usize; // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
- scope 1 {
- debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
- }
- scope 2 {
- debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
- }
- scope 3 {
- debug v => _7; // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
- }
- scope 4 {
- debug r => _9; // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
- _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
- switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
- }
-
- bb1: {
- StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
- StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
- StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
- Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
- discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
- StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
- goto -> bb4; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
- }
-
- bb3: {
- StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
- _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
- StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
- _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
- Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
- ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
- discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
- StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
- StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
- StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
- _7 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
- StorageLive(_8); // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
- _8 = _7; // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
- Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
- ((_0 as Some).0: i32) = move _8; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
- discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
- StorageDead(_8); // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
- StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
- goto -> bb4; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
- }
-
- bb4: {
- StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
- return; // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
- }
-}
// Test that we don't generate unnecessarily large MIR for very simple matches
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR simple_match.match_bool.mir_map.0.mir
fn match_bool(x: bool) -> usize {
match x {
+++ /dev/null
-// MIR for `match_bool` 0 mir_map
-
-fn match_bool(_1: bool) -> usize {
- debug x => _1; // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16
- let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32
-
- bb0: {
- FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12
- switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12
- }
-
- bb1: {
- falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13
- }
-
- bb2: {
- _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
- goto -> bb4; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
- }
-
- bb3: {
- _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
- goto -> bb4; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
- }
-
- bb4: {
- return; // scope 0 at $DIR/simple-match.rs:+5:2: +5:2
- }
-}
+++ /dev/null
-// MIR for `match_bool` 0 mir_map
-
-fn match_bool(_1: bool) -> usize {
- debug x => _1; // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16
- let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32
-
- bb0: {
- FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12
- switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12
- }
-
- bb1: {
- falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13
- }
-
- bb2: {
- _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
- goto -> bb4; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
- }
-
- bb3: {
- _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
- goto -> bb4; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
- }
-
- bb4: {
- return; // scope 0 at $DIR/simple-match.rs:+5:2: +5:2
- }
-}
--- /dev/null
+// MIR for `match_bool` 0 mir_map
+
+fn match_bool(_1: bool) -> usize {
+ debug x => _1; // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16
+ let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32
+
+ bb0: {
+ FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12
+ switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12
+ }
+
+ bb1: {
+ falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13
+ }
+
+ bb2: {
+ _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
+ goto -> bb4; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
+ }
+
+ bb3: {
+ _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
+ goto -> bb4; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
+ }
+
+ bb4: {
+ return; // scope 0 at $DIR/simple-match.rs:+5:2: +5:2
+ }
+}
map(None);
}
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
+++ /dev/null
-- // MIR for `map` before SimplifyLocals
-+ // MIR for `map` after SimplifyLocals
-
- fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
- debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
- let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
-- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
- scope 1 {
- debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- }
-
- bb0: {
-- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
- }
-
- bb1: {
- StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
- _4 = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
- Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
- ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
- discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
- StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
- StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
- goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
- }
-
- bb3: {
- Deinit(_0); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
- discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
- goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
- }
-
- bb4: {
-- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
- return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
- }
- }
-
+++ /dev/null
-- // MIR for `map` before SimplifyLocals
-+ // MIR for `map` after SimplifyLocals
-
- fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
- debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
- let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
-- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
- scope 1 {
- debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- }
-
- bb0: {
-- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
- }
-
- bb1: {
- StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
- _4 = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
- Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
- ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
- discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
- StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
- StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
- goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
- }
-
- bb3: {
- Deinit(_0); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
- discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
- goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
- }
-
- bb4: {
-- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
- return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
- }
- }
-
--- /dev/null
+- // MIR for `map` before SimplifyLocals
++ // MIR for `map` after SimplifyLocals
+
+ fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
+ debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
+ let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
+ let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
+ let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
+- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
+- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
+ scope 1 {
+ debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ }
+
+ bb0: {
+- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+ _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+ switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
+ }
+
+ bb1: {
+ StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+ _4 = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+ Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+ ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+ discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+ StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
+ StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
+ goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
+ }
+
+ bb2: {
+ unreachable; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+ }
+
+ bb3: {
+ Deinit(_0); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
+ discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
+ goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
+ }
+
+ bb4: {
+- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
+ }
+ }
+
// compile-flags: -Zmir-opt-level=0
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
// EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
fn main() {
let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_);
+++ /dev/null
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
- let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
- bb0: {
- goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb1: {
- return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb3 (cleanup): {
- _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb4 (cleanup): {
- _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb5: {
- _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb6: {
- _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb7: {
- _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb8: {
- goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb9 (cleanup): {
- _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb10 (cleanup): {
- _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb11: {
- _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb12: {
- _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb13: {
- _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb14: {
- goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb15: {
- _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-}
+++ /dev/null
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
- let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
- bb0: {
- goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb1: {
- return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb3 (cleanup): {
- _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb4 (cleanup): {
- _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb5: {
- _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb6: {
- _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb7: {
- _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb8: {
- goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb9 (cleanup): {
- _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb10 (cleanup): {
- _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb11: {
- _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb12: {
- _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb13: {
- _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb14: {
- goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb15: {
- _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-}
--- /dev/null
+// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
+
+fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
+ let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+
+ bb0: {
+ goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb1: {
+ return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb3 (cleanup): {
+ _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb4 (cleanup): {
+ _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb5: {
+ _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb6: {
+ _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb7: {
+ _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb8: {
+ goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb9 (cleanup): {
+ _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb10 (cleanup): {
+ _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb11: {
+ _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb12: {
+ _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb13: {
+ _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb14: {
+ goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb15: {
+ _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+}
// Test that we don't ICE when trying to dump MIR for unusual item types and
// that we don't create filenames containing `<` and `>`
// compile-flags: -Zmir-opt-level=0
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
struct A;
+++ /dev/null
-// MIR for `E::V::{constant#0}` 0 mir_map
-
-E::V::{constant#0}: isize = {
- let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-
- bb0: {
- _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
- return; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
- }
-}
+++ /dev/null
-// MIR for `E::V::{constant#0}` 0 mir_map
-
-E::V::{constant#0}: isize = {
- let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-
- bb0: {
- _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
- return; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
- }
-}
--- /dev/null
+// MIR for `E::V::{constant#0}` 0 mir_map
+
+E::V::{constant#0}: isize = {
+ let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
+
+ bb0: {
+ _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
+ return; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
+ }
+}
+++ /dev/null
-// MIR for `Test::X` 0 mir_map
-
-fn Test::X(_1: usize) -> Test {
- let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-
- bb0: {
- Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- }
-}
+++ /dev/null
-// MIR for `Test::X` 0 mir_map
-
-fn Test::X(_1: usize) -> Test {
- let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-
- bb0: {
- Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- }
-}
--- /dev/null
+// MIR for `Test::X` 0 mir_map
+
+fn Test::X(_1: usize) -> Test {
+ let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+
+ bb0: {
+ Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+ ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+ discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+ return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+ }
+}
+++ /dev/null
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
- let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _2: &mut std::vec::Vec<i32>; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
- bb0: {
- goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb1: {
- return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb3: {
- goto -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb4 (cleanup): {
- drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb5: {
- drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb6: {
- _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- // mir::Constant
- // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
- }
-}
+++ /dev/null
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
- let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _2: &mut std::vec::Vec<i32>; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
- bb0: {
- goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb1: {
- return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb3: {
- goto -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb4 (cleanup): {
- drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb5: {
- drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- }
-
- bb6: {
- _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
- // mir::Constant
- // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
- }
-}
--- /dev/null
+// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
+
+fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
+ let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _2: &mut std::vec::Vec<i32>; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+
+ bb0: {
+ goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb1: {
+ return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb3: {
+ goto -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb4 (cleanup): {
+ drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb5: {
+ drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ }
+
+ bb6: {
+ _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
+ }
+}
+++ /dev/null
-// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map
-
-const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = {
- let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35
-
- bb0: {
- _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39
- return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:39
- }
-}
+++ /dev/null
-// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map
-
-const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = {
- let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35
-
- bb0: {
- _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39
- return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:39
- }
-}
--- /dev/null
+// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map
+
+const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = {
+ let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35
+
+ bb0: {
+ _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39
+ return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:39
+ }
+}
+++ /dev/null
-- // MIR for `change_loop_body` before ConstProp
-+ // MIR for `change_loop_body` after ConstProp
-
- fn change_loop_body() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
- let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
- let mut _2: (); // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
- let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
- let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
- let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
- let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
- let _7: (); // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
- let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
- scope 1 {
- debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
- scope 2 {
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
- _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
- StorageLive(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
- Deinit(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
- discriminant(_3) = 0; // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-- _4 = discriminant(_3); // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+ _4 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+ switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
- }
-
- bb1: {
- switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
- }
-
- bb2: {
- _1 = const 1_i32; // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
- nop; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
- goto -> bb4; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
- }
-
- bb3: {
- StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
- nop; // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
- StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
- goto -> bb4; // scope 1 at no-location
- }
-
- bb4: {
- StorageDead(_3); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
- StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
- return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
- }
- }
-
+++ /dev/null
-- // MIR for `change_loop_body` before ConstProp
-+ // MIR for `change_loop_body` after ConstProp
-
- fn change_loop_body() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
- let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
- let mut _2: (); // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
- let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
- let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
- let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
- let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
- let _7: (); // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
- let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
- scope 1 {
- debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
- scope 2 {
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
- _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
- StorageLive(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
- Deinit(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
- discriminant(_3) = 0; // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-- _4 = discriminant(_3); // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+ _4 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+ switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
- }
-
- bb1: {
- switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
- }
-
- bb2: {
- _1 = const 1_i32; // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
- nop; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
- goto -> bb4; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
- }
-
- bb3: {
- StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
- nop; // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
- StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
- goto -> bb4; // scope 1 at no-location
- }
-
- bb4: {
- StorageDead(_3); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
- StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
- return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
- }
- }
-
--- /dev/null
+- // MIR for `change_loop_body` before ConstProp
++ // MIR for `change_loop_body` after ConstProp
+
+ fn change_loop_body() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
+ let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
+ let mut _2: (); // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
+ let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
+ let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
+ let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
+ let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+ let _7: (); // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+ let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+ scope 1 {
+ debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
+ scope 2 {
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
+ _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
+ StorageLive(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+ Deinit(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+ discriminant(_3) = 0; // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+- _4 = discriminant(_3); // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
++ _4 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
++ switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+ }
+
+ bb1: {
+ switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+ }
+
+ bb2: {
+ _1 = const 1_i32; // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
+ nop; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
+ goto -> bb4; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
+ }
+
+ bb3: {
+ StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
+ nop; // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
+ StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
+ goto -> bb4; // scope 1 at no-location
+ }
+
+ bb4: {
+ StorageDead(_3); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
+ StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
+ }
+ }
+
+++ /dev/null
-// MIR for `change_loop_body` after PreCodegen
-
-fn change_loop_body() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
- let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
- scope 1 {
- debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
- scope 2 {
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
- StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
- return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
- }
-}
+++ /dev/null
-// MIR for `change_loop_body` after PreCodegen
-
-fn change_loop_body() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
- let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
- scope 1 {
- debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
- scope 2 {
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
- StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
- return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
- }
-}
--- /dev/null
+// MIR for `change_loop_body` after PreCodegen
+
+fn change_loop_body() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
+ let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
+ scope 1 {
+ debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
+ scope 2 {
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
+ StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
+ }
+}
// EMIT_MIR while_let_loops.change_loop_body.ConstProp.diff
// EMIT_MIR while_let_loops.change_loop_body.PreCodegen.after.mir
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
pub fn change_loop_body() {
let mut _x = 0;
--- /dev/null
+# needs-profiler-support
+# ignore-windows-gnu
+
+-include ../../run-make-fulldeps/tools.mk
+
+# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC`
+# instead of hardcoding them everywhere they're needed.
+ifeq ($(IS_MUSL_HOST),1)
+ADDITIONAL_ARGS := $(RUSTFLAGS)
+endif
+
+all:
+ # Generate PGO profiles
+ $(BARE_RUSTC) $(ADDITIONAL_ARGS) -Cprofile-generate=$(TMPDIR)/profiles --out-dir $(TMPDIR) main.rs
+ $(TMPDIR)/main
+
+ # Merge profiles
+ "$(LLVM_BIN_DIR)/llvm-profdata" merge \
+ -o "$(TMPDIR)/merged.profdata" \
+ "$(TMPDIR)/profiles" || exit 1
+
+ # Use the profile
+ $(RUSTC) -Cprofile-use=$(TMPDIR)/merged.profdata --emit dep-info main.rs
+
+ # Check that profile file is in depinfo
+ $(CGREP) "merged.profdata" < $(TMPDIR)/main.d
--- /dev/null
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied
+ --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13
+ |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+ | ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error[E0782]: trait objects must include the `dyn` keyword
+ --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:24
+ |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+ | ^^^^^^^
+ |
+help: add `dyn` keyword before this trait
+ |
+LL - fn ice() -> impl AsRef<Fn(&())> {
+LL + fn ice() -> impl AsRef<dyn Fn(&())> {
+ |
+
+error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied
+ --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13
+ |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+ | ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0782.
+For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+// revisions: edition2015 edition2021
+//[edition2021]edition:2021
+
+#![allow(warnings)]
+
+fn ice() -> impl AsRef<Fn(&())> {
+ //~^ ERROR: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied [E0277]
+ //[edition2021]~| ERROR: trait objects must include the `dyn` keyword [E0782]
+ todo!()
+}
+
+fn main() {}
|
LL | #[repr(nothing)]
| ^^^^^^^
+ |
+ = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
error[E0552]: unrecognized representation hint
--> $DIR/issue-43988.rs:18:12
|
LL | #[repr(something_not_real)]
| ^^^^^^^^^^^^^^^^^^
+ |
+ = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43988.rs:30:5
--- /dev/null
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+ foo()
+ [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,`
+}
+
+fn main() {}
--- /dev/null
+error: expected one of `.`, `?`, `]`, or an operator, found `,`
+ --> $DIR/do-not-suggest-semicolon-before-array.rs:5:5
+ |
+LL | [1, 3)
+ | ^ ^ help: `]` may belong here
+ | |
+ | unclosed delimiter
+
+error: aborting due to previous error
+
--- /dev/null
+fn main() {
+ let _x = vec[1, 2, 3]; //~ ERROR expected one of `.`, `?`, `]`, or an operator
+}
--- /dev/null
+error: expected one of `.`, `?`, `]`, or an operator, found `,`
+ --> $DIR/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs:2:19
+ |
+LL | let _x = vec[1, 2, 3];
+ | ^ expected one of `.`, `?`, `]`, or an operator
+
+error: aborting due to previous error
+
+++ /dev/null
-fn foo() {}
-
-fn bar() -> [u8; 2] {
- foo()
- [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,`
-}
-
-fn main() {}
+++ /dev/null
-error: expected one of `.`, `?`, `]`, or an operator, found `,`
- --> $DIR/do-not-suggest-suggest-semicolon-before-array.rs:5:5
- |
-LL | [1, 3)
- | ^ ^ help: `]` may belong here
- | |
- | unclosed delimiter
-
-error: aborting due to previous error
-
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+ foo();
+ [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+ foo()
+ [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
--- /dev/null
+error: expected `;`, found `[`
+ --> $DIR/suggest-semicolon-before-array.rs:8:5
+ |
+LL | [1, 3]
+ | ^
+ |
+help: consider adding `;` here
+ |
+LL | foo();
+ | +
+
+error: aborting due to previous error
+
+++ /dev/null
-// run-rustfix
-#![allow(dead_code)]
-
-fn foo() {}
-
-fn bar() -> [u8; 2] {
- foo();
- [1, 3] //~ ERROR expected `;`, found `[`
-}
-
-fn main() {}
+++ /dev/null
-// run-rustfix
-#![allow(dead_code)]
-
-fn foo() {}
-
-fn bar() -> [u8; 2] {
- foo()
- [1, 3] //~ ERROR expected `;`, found `[`
-}
-
-fn main() {}
+++ /dev/null
-error: expected `;`, found `[`
- --> $DIR/suggest-suggest-semicolon-before-array.rs:8:5
- |
-LL | [1, 3]
- | ^
- |
-help: consider adding `;` here
- |
-LL | foo();
- | +
-
-error: aborting due to previous error
-
--- /dev/null
+#![crate_type = "lib"]
+
+#[repr(uwu)] //~ERROR: unrecognized representation hint
+pub struct OwO;
+
+#[repr(uwu = "a")] //~ERROR: unrecognized representation hint
+pub struct OwO2(i32);
+
+#[repr(uwu(4))] //~ERROR: unrecognized representation hint
+pub struct OwO3 {
+ x: i32,
+}
+
+#[repr(uwu, u8)] //~ERROR: unrecognized representation hint
+pub enum OwO4 {
+ UwU = 1,
+}
--- /dev/null
+error[E0552]: unrecognized representation hint
+ --> $DIR/invalid_repr_list_help.rs:3:8
+ |
+LL | #[repr(uwu)]
+ | ^^^
+ |
+ = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0552]: unrecognized representation hint
+ --> $DIR/invalid_repr_list_help.rs:6:8
+ |
+LL | #[repr(uwu = "a")]
+ | ^^^^^^^^^
+ |
+ = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0552]: unrecognized representation hint
+ --> $DIR/invalid_repr_list_help.rs:9:8
+ |
+LL | #[repr(uwu(4))]
+ | ^^^^^^
+ |
+ = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0552]: unrecognized representation hint
+ --> $DIR/invalid_repr_list_help.rs:14:8
+ |
+LL | #[repr(uwu, u8)]
+ | ^^^
+ |
+ = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0552`.
if replaced.insert(param_ty.index) {
for projection_predicate in projection_predicates {
if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
- && let ty::Term::Ty(term_ty) = projection_predicate.term
+ && let Some(term_ty) = projection_predicate.term.ty()
&& let ty::Param(term_param_ty) = term_ty.kind()
{
let item_def_id = projection_predicate.projection_ty.item_def_id;
// one of the associated types must be Self
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
- let assoc_ty = match projection_predicate.term {
- ty::Term::Ty(ty) => ty,
- ty::Term::Const(_c) => continue,
+ let assoc_ty = match projection_predicate.term.unpack() {
+ ty::TermKind::Ty(ty) => ty,
+ ty::TermKind::Const(_c) => continue,
};
// walk the associated type and check for Self
if let Some(self_adt) = self_ty.ty_adt_def() {
.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
implements_trait(cx, receiver_ty, deref_trait_id, &[])
&& get_associated_type(cx, receiver_ty, deref_trait_id, "Target")
- .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
+ .map_or(false, |ty| ty::TermKind::Ty(ty) == normalized_ty.unpack())
} else {
false
}
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{
Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
- TerminatorKind,
+ TerminatorKind, NonDivergingIntrinsic
};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
check_place(tcx, **place, span, body)
},
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+ check_operand(tcx, op, span, body)
+ },
+
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+ rustc_middle::mir::CopyNonOverlapping { dst, src, count },
+ )) => {
check_operand(tcx, dst, span, body)?;
check_operand(tcx, src, span, body)?;
check_operand(tcx, count, span, body)
},
+
// These are all NOPs
StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
-Subproject commit dba35d2be72f4b78343d1a0f0b4737306f310672
+Subproject commit ef3f649e49607a1fad64eb0a5139110df3efa2a7
pull_request:
push:
branches:
- - auto
- - try
+ - auto
+ - try
env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CI: 1
RUST_BACKTRACE: short
- RUSTFLAGS: "-D warnings -W unreachable-pub -W rust-2021-compatibility"
+ RUSTFLAGS: "-D warnings -W unreachable-pub -W bare-trait-objects"
RUSTUP_MAX_RETRIES: 10
jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- - name: Checkout repository
- uses: actions/checkout@v3
- with:
- ref: ${{ github.event.pull_request.head.sha }}
- fetch-depth: 20
+ - name: Checkout repository
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 20
- - name: Install Rust toolchain
- run: |
- rustup update --no-self-update stable
- rustup component add rustfmt rust-src
+ - name: Install Rust toolchain
+ run: |
+ rustup update --no-self-update stable
+ rustup component add rustfmt rust-src
- - name: Cache Dependencies
- uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
+ - name: Cache Dependencies
+ uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
- - name: Compile
- run: cargo test --no-run --locked
+ - name: Compile
+ run: cargo test --no-run --locked
- - name: Test
- run: cargo test -- --nocapture --quiet
+ - name: Test
+ run: cargo test -- --nocapture --quiet
# Weird targets to catch non-portable code
rust-cross:
targets_ide: "wasm32-unknown-unknown"
steps:
- - name: Checkout repository
- uses: actions/checkout@v3
-
- - name: Install Rust toolchain
- run: |
- rustup update --no-self-update stable
- rustup target add ${{ env.targets }} ${{ env.targets_ide }}
-
- - name: Cache Dependencies
- uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
-
- - name: Check
- run: |
- for target in ${{ env.targets }}; do
- cargo check --target=$target --all-targets
- done
- for target in ${{ env.targets_ide }}; do
- cargo check -p ide --target=$target --all-targets
- done
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Install Rust toolchain
+ run: |
+ rustup update --no-self-update stable
+ rustup target add ${{ env.targets }} ${{ env.targets_ide }}
+
+ - name: Cache Dependencies
+ uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
+
+ - name: Check
+ run: |
+ for target in ${{ env.targets }}; do
+ cargo check --target=$target --all-targets
+ done
+ for target in ${{ env.targets_ide }}; do
+ cargo check -p ide --target=$target --all-targets
+ done
typescript:
if: github.repository == 'rust-lang/rust-analyzer'
runs-on: ${{ matrix.os }}
steps:
- - name: Checkout repository
- uses: actions/checkout@v3
-
- - name: Install Nodejs
- uses: actions/setup-node@v1
- with:
- node-version: 16.x
-
- - name: Install xvfb
- if: matrix.os == 'ubuntu-latest'
- run: sudo apt-get install -y xvfb
-
- - run: npm ci
- working-directory: ./editors/code
-
-# - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
-# if: runner.os == 'Linux'
-# working-directory: ./editors/code
-
- - run: npm run lint
- working-directory: ./editors/code
-
- - name: Run VS Code tests (Linux)
- if: matrix.os == 'ubuntu-latest'
- env:
- VSCODE_CLI: 1
- run: xvfb-run npm test
- working-directory: ./editors/code
-
- - name: Run VS Code tests (Windows)
- if: matrix.os == 'windows-latest'
- env:
- VSCODE_CLI: 1
- run: npm test
- working-directory: ./editors/code
-
- - run: npm run pretest
- working-directory: ./editors/code
-
- - run: npm run package --scripts-prepend-node-path
- working-directory: ./editors/code
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Install Nodejs
+ uses: actions/setup-node@v1
+ with:
+ node-version: 16.x
+
+ - name: Install xvfb
+ if: matrix.os == 'ubuntu-latest'
+ run: sudo apt-get install -y xvfb
+
+ - run: npm ci
+ working-directory: ./editors/code
+
+ # - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
+ # if: runner.os == 'Linux'
+ # working-directory: ./editors/code
+
+ - run: npm run lint
+ working-directory: ./editors/code
+
+ - name: Run VS Code tests (Linux)
+ if: matrix.os == 'ubuntu-latest'
+ env:
+ VSCODE_CLI: 1
+ run: xvfb-run npm test
+ working-directory: ./editors/code
+
+ - name: Run VS Code tests (Windows)
+ if: matrix.os == 'windows-latest'
+ env:
+ VSCODE_CLI: 1
+ run: npm test
+ working-directory: ./editors/code
+
+ - run: npm run pretest
+ working-directory: ./editors/code
+
+ - run: npm run package --scripts-prepend-node-path
+ working-directory: ./editors/code
end-success:
name: bors build finished
if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
working-directory: ./editors/code
# token from https://dev.azure.com/rust-analyzer/
- run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
+ run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
- name: Publish Extension (Code Marketplace, nightly)
if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
- name: Publish Extension (OpenVSX, nightly)
if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
working-directory: ./editors/code
- run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
+ run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
pub type LabelPtr = AstPtr<ast::Label>;
pub type LabelSource = InFile<LabelPtr>;
+
+pub type FieldPtr = AstPtr<ast::RecordExprField>;
+pub type FieldSource = InFile<FieldPtr>;
+
/// An item body together with the mapping from syntax nodes to HIR expression
/// IDs. This is needed to go from e.g. a position in a file to the HIR
/// expression containing it; but for type inference etc., we want to operate on
#[derive(Default, Debug, Eq, PartialEq)]
pub struct BodySourceMap {
expr_map: FxHashMap<ExprSource, ExprId>,
- expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
+ expr_map_back: ArenaMap<ExprId, ExprSource>,
pat_map: FxHashMap<PatSource, PatId>,
- pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
+ pat_map_back: ArenaMap<PatId, PatSource>,
label_map: FxHashMap<LabelSource, LabelId>,
label_map_back: ArenaMap<LabelId, LabelSource>,
/// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
/// Instead, we use id of expression (`92`) to identify the field.
- field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>,
- field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>,
+ field_map: FxHashMap<FieldSource, ExprId>,
+ field_map_back: FxHashMap<ExprId, FieldSource>,
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
// Perhaps `expr_syntax` and `expr_id`?
impl BodySourceMap {
pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
- self.expr_map_back[expr].clone()
+ self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
}
pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
}
pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
- self.pat_map_back[pat].clone()
+ self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
}
pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
self.label_map.get(&src).cloned()
}
- pub fn field_syntax(&self, expr: ExprId) -> InFile<AstPtr<ast::RecordExprField>> {
+ pub fn field_syntax(&self, expr: ExprId) -> FieldSource {
self.field_map_back[&expr].clone()
}
+
pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId> {
let src = node.map(AstPtr::new);
self.field_map.get(&src).cloned()
use crate::{
adt::StructKind,
- body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
+ body::{Body, BodySourceMap, Expander, ExprPtr, LabelPtr, LabelSource, PatPtr},
body::{BodyDiagnostic, ExprSource, PatSource},
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
db::DefDatabase,
LowerCtx::new(self.db, self.expander.current_file_id)
}
- fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
+ fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
let src = self.expander.to_source(ptr);
- let id = self.make_expr(expr, Ok(src.clone()));
+ let id = self.make_expr(expr, src.clone());
self.source_map.expr_map.insert(src, id);
id
}
// desugared exprs don't have ptr, that's wrong and should be fixed
// somehow.
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
- self.make_expr(expr, Err(SyntheticSyntax))
+ self.body.exprs.alloc(expr)
}
fn missing_expr(&mut self) -> ExprId {
self.alloc_expr_desugared(Expr::Missing)
}
- fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
+ fn make_expr(&mut self, expr: Expr, src: ExprSource) -> ExprId {
let id = self.body.exprs.alloc(expr);
self.source_map.expr_map_back.insert(id, src);
id
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
let src = self.expander.to_source(ptr);
- let id = self.make_pat(pat, Ok(src.clone()));
+ let id = self.make_pat(pat, src.clone());
self.source_map.pat_map.insert(src, id);
id
}
fn missing_pat(&mut self) -> PatId {
- self.make_pat(Pat::Missing, Err(SyntheticSyntax))
+ self.body.pats.alloc(Pat::Missing)
}
- fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
+ fn make_pat(&mut self, pat: Pat, src: PatSource) -> PatId {
let id = self.body.pats.alloc(pat);
self.source_map.pat_map_back.insert(id, src);
id
}
- fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
+ fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
let src = self.expander.to_source(ptr);
let id = self.make_label(label, src.clone());
self.source_map.label_map.insert(src, id);
None => self.alloc_expr(Expr::Missing, syntax_ptr),
}
}
- ast::Expr::MacroStmts(e) => {
- let statements: Box<[_]> =
- e.statements().filter_map(|s| self.collect_stmt(s)).collect();
- let tail = e.expr().map(|e| self.collect_expr(e));
-
- if e.syntax().children().next().is_none() {
- // HACK: make sure that macros that expand to nothing aren't treated as a `()`
- // expression when used in block tail position.
- cov_mark::hit!(empty_macro_in_trailing_position_is_removed);
- return None;
- }
-
- self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr)
- }
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
})
}
}
}
- fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Statement> {
+ fn collect_macro_as_stmt(
+ &mut self,
+ statements: &mut Vec<Statement>,
+ mac: ast::MacroExpr,
+ ) -> Option<ExprId> {
+ let mac_call = mac.macro_call()?;
+ let syntax_ptr = AstPtr::new(&ast::Expr::from(mac));
+ let macro_ptr = AstPtr::new(&mac_call);
+ let expansion = self.collect_macro_call(
+ mac_call,
+ macro_ptr,
+ false,
+ |this, expansion: Option<ast::MacroStmts>| match expansion {
+ Some(expansion) => {
+ expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt));
+ expansion.expr().and_then(|expr| match expr {
+ ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac),
+ expr => Some(this.collect_expr(expr)),
+ })
+ }
+ None => None,
+ },
+ );
+ match expansion {
+ Some(tail) => {
+ // Make the macro-call point to its expanded expression so we can query
+ // semantics on syntax pointers to the macro
+ let src = self.expander.to_source(syntax_ptr);
+ self.source_map.expr_map.insert(src, tail);
+ Some(tail)
+ }
+ None => None,
+ }
+ }
+
+ fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) {
match s {
ast::Stmt::LetStmt(stmt) => {
if self.check_cfg(&stmt).is_none() {
- return None;
+ return;
}
let pat = self.collect_pat_opt(stmt.pat());
let type_ref =
.let_else()
.and_then(|let_else| let_else.block_expr())
.map(|block| self.collect_block(block));
- Some(Statement::Let { pat, type_ref, initializer, else_branch })
+ statements.push(Statement::Let { pat, type_ref, initializer, else_branch });
}
ast::Stmt::ExprStmt(stmt) => {
let expr = stmt.expr();
- if let Some(expr) = &expr {
- if self.check_cfg(expr).is_none() {
- return None;
- }
+ match &expr {
+ Some(expr) if self.check_cfg(expr).is_none() => return,
+ _ => (),
}
let has_semi = stmt.semicolon_token().is_some();
// Note that macro could be expanded to multiple statements
- if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr {
- let mac_call = mac.macro_call()?;
- let syntax_ptr = AstPtr::new(expr);
- let macro_ptr = AstPtr::new(&mac_call);
- let stmt = self.collect_macro_call(
- mac_call,
- macro_ptr,
- false,
- |this, expansion: Option<ast::MacroStmts>| match expansion {
- Some(expansion) => {
- let statements = expansion
- .statements()
- .filter_map(|stmt| this.collect_stmt(stmt))
- .collect();
- let tail = expansion.expr().map(|expr| this.collect_expr(expr));
-
- let mac_stmts = this.alloc_expr(
- Expr::MacroStmts { tail, statements },
- AstPtr::new(&ast::Expr::MacroStmts(expansion)),
- );
-
- Some(mac_stmts)
- }
- None => None,
- },
- );
-
- let expr = match stmt {
- Some(expr) => {
- // Make the macro-call point to its expanded expression so we can query
- // semantics on syntax pointers to the macro
- let src = self.expander.to_source(syntax_ptr);
- self.source_map.expr_map.insert(src, expr);
- expr
- }
- None => self.alloc_expr(Expr::Missing, syntax_ptr),
- };
- Some(Statement::Expr { expr, has_semi })
+ if let Some(ast::Expr::MacroExpr(mac)) = expr {
+ if let Some(expr) = self.collect_macro_as_stmt(statements, mac) {
+ statements.push(Statement::Expr { expr, has_semi })
+ }
} else {
let expr = self.collect_expr_opt(expr);
- Some(Statement::Expr { expr, has_semi })
+ statements.push(Statement::Expr { expr, has_semi });
}
}
- ast::Stmt::Item(_item) => None,
+ ast::Stmt::Item(_item) => (),
}
}
let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
let prev_local_module = mem::replace(&mut self.expander.module, module);
- let mut statements: Vec<_> =
- block.statements().filter_map(|s| self.collect_stmt(s)).collect();
- let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e));
+ let mut statements = Vec::new();
+ block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
+ let tail = block.tail_expr().and_then(|e| match e {
+ ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac),
+ expr => self.maybe_collect_expr(expr),
+ });
let tail = tail.or_else(|| {
let stmt = statements.pop()?;
if let Statement::Expr { expr, has_semi: false } = stmt {
}
w!(self, "}}");
}
- Expr::MacroStmts { statements, tail } => {
- w!(self, "{{ // macro statements");
- self.indented(|p| {
- for stmt in statements.iter() {
- p.print_stmt(stmt);
- }
- if let Some(tail) = tail {
- p.print_expr(*tail);
- }
- });
- self.newline();
- w!(self, "}}");
- }
}
}
impl ExprScopes {
pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
let body = db.body(def);
- Arc::new(ExprScopes::new(&*body))
- }
-
- fn new(body: &Body) -> ExprScopes {
- let mut scopes =
- ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
- let mut root = scopes.root_scope();
- scopes.add_params_bindings(body, root, &body.params);
- compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
- scopes
+ let mut scopes = ExprScopes::new(&*body);
+ scopes.shrink_to_fit();
+ Arc::new(scopes)
}
pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
pub fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> {
&self.scope_by_expr
}
+}
+
+impl ExprScopes {
+ fn new(body: &Body) -> ExprScopes {
+ let mut scopes =
+ ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
+ let mut root = scopes.root_scope();
+ scopes.add_params_bindings(body, root, &body.params);
+ compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
+ scopes
+ }
fn root_scope(&mut self) -> ScopeId {
self.scopes.alloc(ScopeData { parent: None, block: None, label: None, entries: vec![] })
fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
self.scope_by_expr.insert(node, scope);
}
+
+ fn shrink_to_fit(&mut self) {
+ let ExprScopes { scopes, scope_by_expr } = self;
+ scopes.shrink_to_fit();
+ scopes.values_mut().for_each(|it| it.entries.shrink_to_fit());
+ scope_by_expr.shrink_to_fit();
+ }
}
fn compute_block_scopes(
scopes.set_scope(expr, *scope);
match &body[expr] {
- Expr::MacroStmts { statements, tail } => {
- compute_block_scopes(statements, *tail, body, scopes, scope);
- }
Expr::Block { statements, tail, id, label } => {
let mut scope = scopes.new_block_scope(*scope, *id, make_label(label));
// Overwrite the old scope for the block expr, so that every block scope can be found
Unsafe {
body: ExprId,
},
- MacroStmts {
- statements: Box<[Statement]>,
- tail: Option<ExprId>,
- },
Array(Array),
Literal(Literal),
Underscore,
Expr::Let { expr, .. } => {
f(*expr);
}
- Expr::MacroStmts { tail, statements } | Expr::Block { statements, tail, .. } => {
+ Expr::Block { statements, tail, .. } => {
for stmt in statements.iter() {
match stmt {
Statement::Let { initializer, .. } => {
use itertools::Itertools;
use la_arena::Arena;
use profile::Count;
-use rustc_hash::FxHashMap;
+use rustc_hash::{FxHashMap, FxHashSet};
use stdx::format_to;
use syntax::{ast, SmolStr};
/// The prelude module for this crate. This either comes from an import
/// marked with the `prelude_import` attribute, or (in the normal case) from
/// a dependency (`std` or `core`).
+ /// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used,
+ /// but that attribute is nightly and when used in a block, it affects resolution globally
+ /// so we aren't handling this correctly anyways).
prelude: Option<ModuleId>,
+ /// The extern prelude is only populated for non-block DefMaps
extern_prelude: FxHashMap<Name, ModuleId>,
/// Side table for resolving derive helpers.
registered_attrs: Vec<SmolStr>,
/// Custom tool modules registered with `#![register_tool]`.
registered_tools: Vec<SmolStr>,
+ /// Unstable features of Rust enabled with `#![feature(A, B)]`.
+ unstable_features: FxHashSet<SmolStr>,
edition: Edition,
recursion_limit: Option<u32>,
modules,
registered_attrs: Vec::new(),
registered_tools: Vec::new(),
+ unstable_features: FxHashSet::default(),
diagnostics: Vec::new(),
}
}
&self.registered_attrs
}
+ pub fn is_unstable_feature_enabled(&self, feature: &str) -> bool {
+ self.unstable_features.contains(feature)
+ }
+
pub fn root(&self) -> LocalModuleId {
self.root
}
registered_tools,
fn_proc_macro_mapping,
derive_helpers_in_scope,
+ unstable_features,
proc_macro_loading_error: _,
block: _,
edition: _,
registered_tools.shrink_to_fit();
fn_proc_macro_mapping.shrink_to_fit();
derive_helpers_in_scope.shrink_to_fit();
+ unstable_features.shrink_to_fit();
for (_, module) in modules.iter_mut() {
module.children.shrink_to_fit();
module.scope.shrink_to_fit();
continue;
}
+ if *attr_name == hir_expand::name![feature] {
+ let features =
+ attr.parse_path_comma_token_tree().into_iter().flatten().filter_map(
+ |feat| match feat.segments() {
+ [name] => Some(name.to_smol_str()),
+ _ => None,
+ },
+ );
+ self.def_map.unstable_features.extend(features);
+ }
+
let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
|| *attr_name == hir_expand::name![register_tool];
if !attr_is_register_like {
Edition::Edition2021 => name![rust_2021],
};
- let path_kind = if self.def_map.edition == Edition::Edition2015 {
- PathKind::Plain
- } else {
- PathKind::Abs
+ let path_kind = match self.def_map.edition {
+ Edition::Edition2015 => PathKind::Plain,
+ _ => PathKind::Abs,
};
let path =
ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
match per_ns.types {
Some((ModuleDefId::ModuleId(m), _)) => {
self.def_map.prelude = Some(m);
- return;
}
types => {
tracing::debug!(
tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
- if import.is_extern_crate && module_id == self.def_map.root {
+ if import.is_extern_crate
+ && self.def_map.block.is_none()
+ && module_id == self.def_map.root
+ {
if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
{
self.def_map.extern_prelude.insert(name.clone(), def);
name: &Name,
attr_path: Option<&SmolStr>,
) -> Result<(FileId, bool, ModDir), Box<[String]>> {
+ let name = name.unescaped();
let orig_file_id = file_id.original_file(db.upcast());
let mut candidate_files = ArrayVec::<_, 2>::new();
candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
}
None if file_id.is_include_macro(db.upcast()) => {
- let name = name.unescaped();
candidate_files.push(format!("{}.rs", name));
candidate_files.push(format!("{}/mod.rs", name));
}
None => {
- let name = name.unescaped();
candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
}
use self::r#async::Bar;
//- /async.rs
+mod foo;
+mod r#async;
pub struct Bar;
+
+//- /async/foo.rs
+pub struct Foo;
+
+//- /async/async.rs
+pub struct Baz;
"#,
expect![[r#"
crate
crate::r#async
Bar: t v
+ foo: t
+ r#async: t
+
+ crate::r#async::foo
+ Foo: t v
+
+ crate::r#async::r#async
+ Baz: t v
"#]],
);
}
///
/// When using, you generally want to process the scopes in reverse order,
/// there's `scopes` *method* for that.
- ///
- /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec.
scopes: Vec<Scope>,
+ module_scope: ModuleItemMap,
}
-// FIXME how to store these best
#[derive(Debug, Clone)]
struct ModuleItemMap {
def_map: Arc<DefMap>,
#[derive(Debug, Clone)]
enum Scope {
/// All the items and imported names of a module
- ModuleScope(ModuleItemMap),
+ BlockScope(ModuleItemMap),
/// Brings the generic parameters of an item into scope
GenericParams { def: GenericDefId, params: Interned<GenericParams> },
/// Brings `Self` in `impl` block into scope
}
}
- fn scopes(&self) -> impl Iterator<Item = &Scope> {
- self.scopes.iter().rev()
- }
-
- fn resolve_module_path(
- &self,
- db: &dyn DefDatabase,
- path: &ModPath,
- shadow: BuiltinShadowMode,
- ) -> PerNs {
- let (item_map, module) = self.module_scope();
- let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
- if segment_index.is_some() {
- return PerNs::none();
- }
- module_res
- }
-
pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs {
self.resolve_module_path(db, path, BuiltinShadowMode::Module)
}
db: &dyn DefDatabase,
path: &ModPath,
) -> Option<PerNs> {
- let (item_map, module) = self.module_scope();
+ let (item_map, module) = self.item_scope();
let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
match module_res.take_types()? {
ModuleDefId::TraitId(it) => {
) -> Option<(TypeNs, Option<usize>)> {
let first_name = path.segments().first()?;
let skip_to_mod = path.kind != PathKind::Plain;
+ if skip_to_mod {
+ return self.module_scope.resolve_path_in_type_ns(db, path);
+ }
+
+ let remaining_idx = || if path.segments().len() == 1 { None } else { Some(1) };
+
for scope in self.scopes() {
match scope {
Scope::ExprScope(_) => continue,
- Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
-
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_type_by_name(first_name, *def) {
- let idx = if path.segments().len() == 1 { None } else { Some(1) };
- return Some((TypeNs::GenericParam(id), idx));
+ return Some((TypeNs::GenericParam(id), remaining_idx()));
}
}
- Scope::ImplDefScope(impl_) => {
+ &Scope::ImplDefScope(impl_) => {
if first_name == &name![Self] {
- let idx = if path.segments().len() == 1 { None } else { Some(1) };
- return Some((TypeNs::SelfType(*impl_), idx));
+ return Some((TypeNs::SelfType(impl_), remaining_idx()));
}
}
- Scope::AdtScope(adt) => {
+ &Scope::AdtScope(adt) => {
if first_name == &name![Self] {
- let idx = if path.segments().len() == 1 { None } else { Some(1) };
- return Some((TypeNs::AdtSelfType(*adt), idx));
+ return Some((TypeNs::AdtSelfType(adt), remaining_idx()));
}
}
- Scope::ModuleScope(m) => {
+ Scope::BlockScope(m) => {
if let Some(res) = m.resolve_path_in_type_ns(db, path) {
return Some(res);
}
}
}
}
- None
+ self.module_scope.resolve_path_in_type_ns(db, path)
}
pub fn resolve_path_in_type_ns_fully(
) -> Option<Visibility> {
match visibility {
RawVisibility::Module(_) => {
- let (item_map, module) = self.module_scope();
+ let (item_map, module) = self.item_scope();
item_map.resolve_visibility(db, module, visibility)
}
RawVisibility::Public => Some(Visibility::Public),
let tmp = name![self];
let first_name = if path.is_self() { &tmp } else { path.segments().first()? };
let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
+ if skip_to_mod {
+ return self.module_scope.resolve_path_in_value_ns(db, path);
+ }
+
for scope in self.scopes() {
match scope {
- Scope::AdtScope(_)
- | Scope::ExprScope(_)
- | Scope::GenericParams { .. }
- | Scope::ImplDefScope(_)
- if skip_to_mod =>
- {
- continue
- }
-
- Scope::ExprScope(scope) if n_segments <= 1 => {
+ Scope::ExprScope(_) if n_segments > 1 => continue,
+ Scope::ExprScope(scope) => {
let entry = scope
.expr_scopes
.entries(scope.scope_id)
return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat())));
}
}
- Scope::ExprScope(_) => continue,
-
Scope::GenericParams { params, def } if n_segments > 1 => {
if let Some(id) = params.find_type_by_name(first_name, *def) {
let ty = TypeNs::GenericParam(id);
return Some(ResolveValueResult::Partial(ty, 1));
}
}
- Scope::GenericParams { params, def } if n_segments == 1 => {
+ Scope::GenericParams { .. } if n_segments != 1 => continue,
+ Scope::GenericParams { params, def } => {
if let Some(id) = params.find_const_by_name(first_name, *def) {
let val = ValueNs::GenericParam(id);
return Some(ResolveValueResult::ValueNs(val));
}
}
- Scope::GenericParams { .. } => continue,
- Scope::ImplDefScope(impl_) => {
+ &Scope::ImplDefScope(impl_) => {
if first_name == &name![Self] {
- if n_segments > 1 {
- let ty = TypeNs::SelfType(*impl_);
- return Some(ResolveValueResult::Partial(ty, 1));
+ return Some(if n_segments > 1 {
+ ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1)
} else {
- return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(*impl_)));
- }
+ ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_))
+ });
}
}
+ // bare `Self` doesn't work in the value namespace in a struct/enum definition
+ Scope::AdtScope(_) if n_segments == 1 => continue,
Scope::AdtScope(adt) => {
- if n_segments == 1 {
- // bare `Self` doesn't work in the value namespace in a struct/enum definition
- continue;
- }
if first_name == &name![Self] {
let ty = TypeNs::AdtSelfType(*adt);
return Some(ResolveValueResult::Partial(ty, 1));
}
}
- Scope::ModuleScope(m) => {
+ Scope::BlockScope(m) => {
if let Some(def) = m.resolve_path_in_value_ns(db, path) {
return Some(def);
}
}
}
+ if let res @ Some(_) = self.module_scope.resolve_path_in_value_ns(db, path) {
+ return res;
+ }
+
// If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back
// to resolving to the primitive type, to allow this to still work in the presence of
// `use core::u16;`.
if path.kind == PathKind::Plain && path.segments().len() > 1 {
- match BuiltinType::by_name(&path.segments()[0]) {
- Some(builtin) => {
- return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
- }
- None => {}
+ if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) {
+ return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
}
}
}
pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
- let (item_map, module) = self.module_scope();
+ let (item_map, module) = self.item_scope();
item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
}
for scope in self.scopes() {
scope.process_names(&mut res, db);
}
+ let ModuleItemMap { ref def_map, module_id } = self.module_scope;
+ // FIXME: should we provide `self` here?
+ // f(
+ // Name::self_param(),
+ // PerNs::types(Resolution::Def {
+ // def: m.module.into(),
+ // }),
+ // );
+ def_map[module_id].scope.entries().for_each(|(name, def)| {
+ res.add_per_ns(name, def);
+ });
+ def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| {
+ macs.iter().for_each(|&mac| {
+ res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))));
+ })
+ });
+ def_map.extern_prelude().for_each(|(name, &def)| {
+ res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
+ });
+ BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
+ res.add_per_ns(name, def);
+ });
+ if let Some(prelude) = def_map.prelude() {
+ let prelude_def_map = prelude.def_map(db);
+ for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
+ res.add_per_ns(name, def)
+ }
+ }
res.map
}
pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
let mut traits = FxHashSet::default();
+
for scope in self.scopes() {
match scope {
- Scope::ModuleScope(m) => {
- if let Some(prelude) = m.def_map.prelude() {
- let prelude_def_map = prelude.def_map(db);
- traits.extend(prelude_def_map[prelude.local_id].scope.traits());
- }
- traits.extend(m.def_map[m.module_id].scope.traits());
-
- // Add all traits that are in scope because of the containing DefMaps
- m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
- if let Some(prelude) = def_map.prelude() {
- let prelude_def_map = prelude.def_map(db);
- traits.extend(prelude_def_map[prelude.local_id].scope.traits());
- }
- traits.extend(def_map[module].scope.traits());
- None::<()>
- });
- }
+ Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()),
&Scope::ImplDefScope(impl_) => {
if let Some(target_trait) = &db.impl_data(impl_).target_trait {
if let Some(TypeNs::TraitId(trait_)) =
_ => (),
}
}
- traits
- }
- fn module_scope(&self) -> (&DefMap, LocalModuleId) {
- self.scopes()
- .find_map(|scope| match scope {
- Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
- _ => None,
- })
- .expect("module scope invariant violated")
+ // Fill in the prelude traits
+ if let Some(prelude) = self.module_scope.def_map.prelude() {
+ let prelude_def_map = prelude.def_map(db);
+ traits.extend(prelude_def_map[prelude.local_id].scope.traits());
+ }
+ // Fill in module visible traits
+ traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits());
+ traits
}
pub fn module(&self) -> ModuleId {
- let (def_map, local_id) = self.module_scope();
+ let (def_map, local_id) = self.item_scope();
def_map.module_id(local_id)
}
pub fn krate(&self) -> CrateId {
- self.def_map().krate()
+ self.module_scope.def_map.krate()
}
pub fn def_map(&self) -> &DefMap {
- self.scopes
- .get(0)
- .and_then(|scope| match scope {
- Scope::ModuleScope(m) => Some(&m.def_map),
- _ => None,
- })
- .expect("module scope invariant violated")
+ self.item_scope().0
}
pub fn where_predicates_in_scope(
}
}
+impl Resolver {
+ fn scopes(&self) -> impl Iterator<Item = &Scope> {
+ self.scopes.iter().rev()
+ }
+
+ fn resolve_module_path(
+ &self,
+ db: &dyn DefDatabase,
+ path: &ModPath,
+ shadow: BuiltinShadowMode,
+ ) -> PerNs {
+ let (item_map, module) = self.item_scope();
+ let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
+ if segment_index.is_some() {
+ return PerNs::none();
+ }
+ module_res
+ }
+
+ /// The innermost block scope that contains items or the module scope that contains this resolver.
+ fn item_scope(&self) -> (&DefMap, LocalModuleId) {
+ self.scopes()
+ .find_map(|scope| match scope {
+ Scope::BlockScope(m) => Some((&*m.def_map, m.module_id)),
+ _ => None,
+ })
+ .unwrap_or((&self.module_scope.def_map, self.module_scope.module_id))
+ }
+}
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ScopeDef {
ModuleDef(ModuleDefId),
impl Scope {
fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
match self {
- Scope::ModuleScope(m) => {
- // FIXME: should we provide `self` here?
- // f(
- // Name::self_param(),
- // PerNs::types(Resolution::Def {
- // def: m.module.into(),
- // }),
- // );
+ Scope::BlockScope(m) => {
m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
acc.add_per_ns(name, def);
});
);
})
});
- m.def_map.extern_prelude().for_each(|(name, &def)| {
- acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
- });
- BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
- acc.add_per_ns(name, def);
- });
- if let Some(prelude) = m.def_map.prelude() {
- let prelude_def_map = prelude.def_map(db);
- for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
- acc.add_per_ns(name, def)
- }
- }
}
Scope::GenericParams { params, def: parent } => {
let parent = *parent;
if let Some(block) = scopes.block(scope) {
if let Some(def_map) = db.block_def_map(block) {
let root = def_map.root();
- r = r.push_module_scope(def_map, root);
+ r = r.push_block_scope(def_map, root);
// FIXME: This adds as many module scopes as there are blocks, but resolving in each
// already traverses all parents, so this is O(n²). I think we could only store the
// innermost module scope instead?
self.push_scope(Scope::ImplDefScope(impl_def))
}
- fn push_module_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
- self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id }))
+ fn push_block_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
+ self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, module_id }))
}
fn push_expr_scope(
impl HasResolver for ModuleId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
let mut def_map = self.def_map(db);
- let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)];
+ let mut modules: SmallVec<[_; 1]> = smallvec![];
+ let mut module_id = self.local_id;
while let Some(parent) = def_map.parent() {
+ modules.push((def_map, module_id));
def_map = parent.def_map(db);
- modules.push((def_map.clone(), parent.local_id));
+ module_id = parent.local_id;
}
- let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) };
+ let mut resolver = Resolver {
+ scopes: Vec::with_capacity(modules.len()),
+ module_scope: ModuleItemMap { def_map, module_id },
+ };
for (def_map, module) in modules.into_iter().rev() {
- resolver = resolver.push_module_scope(def_map, module);
+ resolver = resolver.push_block_scope(def_map, module);
}
resolver
}
if parent.kind() == MACRO_EXPR
&& parent
.parent()
- .map_or(true, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
+ .map_or(false, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
{
return ExpandTo::Statements;
}
test,
test_case,
recursion_limit,
+ feature,
// Safe intrinsics
abort,
add_with_overflow,
fn builtin_deref(ty: &Ty) -> Option<&Ty> {
match ty.kind(Interner) {
- TyKind::Ref(.., ty) => Some(ty),
- TyKind::Raw(.., ty) => Some(ty),
+ TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty),
_ => None,
}
}
}
let pattern_arena = Arena::new();
- let cx = MatchCheckCtx {
- module: self.owner.module(db.upcast()),
- body: self.owner,
- db,
- pattern_arena: &pattern_arena,
- };
+ let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena);
let mut m_arms = Vec::with_capacity(arms.len());
let mut has_lowering_errors = false;
use smallvec::{smallvec, SmallVec};
use stdx::never;
-use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind};
+use crate::{
+ infer::normalize, inhabitedness::is_enum_variant_uninhabited_from, AdtId, Interner, Scalar, Ty,
+ TyExt, TyKind,
+};
use super::{
is_box,
TyKind::Scalar(Scalar::Bool) => smallvec![make_range(0, 1, Scalar::Bool)],
// TyKind::Array(..) if ... => unhandled(),
TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
- &TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => {
- let enum_data = cx.db.enum_data(enum_id);
+ TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), subst) => {
+ let enum_data = cx.db.enum_data(*enum_id);
// If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
// additional "unknown" constructor.
let mut ctors: SmallVec<[_; 1]> = enum_data
.variants
.iter()
- .filter(|&(_, _v)| {
+ .map(|(local_id, _)| EnumVariantId { parent: *enum_id, local_id })
+ .filter(|&variant| {
// If `exhaustive_patterns` is enabled, we exclude variants known to be
// uninhabited.
let is_uninhabited = is_exhaustive_pat_feature
- && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()");
+ && is_enum_variant_uninhabited_from(variant, subst, cx.module, cx.db);
!is_uninhabited
})
- .map(|(local_id, _)| Variant(EnumVariantId { parent: enum_id, local_id }))
+ .map(Variant)
.collect();
if is_secretly_empty || is_declared_nonexhaustive {
use smallvec::{smallvec, SmallVec};
use typed_arena::Arena;
-use crate::{db::HirDatabase, Ty, TyExt};
+use crate::{db::HirDatabase, inhabitedness::is_ty_uninhabited_from, Ty, TyExt};
use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard};
pub(crate) db: &'a dyn HirDatabase,
/// Lowered patterns from arms plus generated by the check.
pub(crate) pattern_arena: &'p Arena<DeconstructedPat<'p>>,
+ exhaustive_patterns: bool,
}
impl<'a, 'p> MatchCheckCtx<'a, 'p> {
- pub(super) fn is_uninhabited(&self, _ty: &Ty) -> bool {
- // FIXME(iDawer) implement exhaustive_patterns feature. More info in:
- // Tracking issue for RFC 1872: exhaustive_patterns feature https://github.com/rust-lang/rust/issues/51085
- false
+ pub(crate) fn new(
+ module: ModuleId,
+ body: DefWithBodyId,
+ db: &'a dyn HirDatabase,
+ pattern_arena: &'p Arena<DeconstructedPat<'p>>,
+ ) -> Self {
+ let def_map = db.crate_def_map(module.krate());
+ let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns");
+ Self { module, body, db, pattern_arena, exhaustive_patterns }
+ }
+
+ pub(super) fn is_uninhabited(&self, ty: &Ty) -> bool {
+ if self.feature_exhaustive_patterns() {
+ is_ty_uninhabited_from(ty, self.module, self.db)
+ } else {
+ false
+ }
}
/// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
}
}
- // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
+ // Rust's unstable feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
pub(super) fn feature_exhaustive_patterns(&self) -> bool {
- // FIXME see MatchCheckCtx::is_uninhabited
- false
+ self.exhaustive_patterns
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum InferenceDiagnostic {
NoSuchField { expr: ExprId },
- BreakOutsideOfLoop { expr: ExprId },
+ BreakOutsideOfLoop { expr: ExprId, is_break: bool },
MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
}
#[derive(Clone, Debug)]
struct BreakableContext {
+ /// Whether this context contains at least one break expression.
may_break: bool,
+ /// The coercion target of the context.
coerce: CoerceMany,
+ /// The optional label of the context.
label: Option<name::Name>,
+ kind: BreakableKind,
+}
+
+#[derive(Clone, Debug)]
+enum BreakableKind {
+ Block,
+ Loop,
+ /// A border is something like an async block, closure etc. Anything that prevents
+ /// breaking/continuing through
+ Border,
}
fn find_breakable<'c>(
ctxs: &'c mut [BreakableContext],
label: Option<&name::Name>,
+) -> Option<&'c mut BreakableContext> {
+ let mut ctxs = ctxs
+ .iter_mut()
+ .rev()
+ .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
+ match label {
+ Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label),
+ None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
+ }
+}
+
+fn find_continuable<'c>(
+ ctxs: &'c mut [BreakableContext],
+ label: Option<&name::Name>,
) -> Option<&'c mut BreakableContext> {
match label {
- Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
- None => ctxs.last_mut(),
+ Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
+ None => find_breakable(ctxs, label),
}
}
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
};
use hir_def::{
- expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp},
+ expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
generics::TypeOrConstParamData,
path::{GenericArg, GenericArgs},
resolver::resolver_for_expr,
use crate::{
autoderef::{self, Autoderef},
consteval,
- infer::coerce::CoerceMany,
+ infer::{coerce::CoerceMany, find_continuable, BreakableKind},
lower::{
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
},
let ty = match label {
Some(_) => {
let break_ty = self.table.new_type_var();
- self.breakables.push(BreakableContext {
- may_break: false,
- coerce: CoerceMany::new(break_ty.clone()),
- label: label.map(|label| self.body[label].name.clone()),
- });
- let ty = self.infer_block(
- tgt_expr,
- statements,
- *tail,
- &Expectation::has_type(break_ty),
+ let (breaks, ty) = self.with_breakable_ctx(
+ BreakableKind::Block,
+ break_ty.clone(),
+ *label,
+ |this| {
+ this.infer_block(
+ tgt_expr,
+ statements,
+ *tail,
+ &Expectation::has_type(break_ty),
+ )
+ },
);
- let ctxt = self.breakables.pop().expect("breakable stack broken");
- if ctxt.may_break {
- ctxt.coerce.complete()
- } else {
- ty
- }
+ breaks.unwrap_or(ty)
}
None => self.infer_block(tgt_expr, statements, *tail, expected),
};
self.resolver = old_resolver;
ty
}
- Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
+ Expr::Unsafe { body } => self.infer_expr(*body, expected),
+ Expr::Const { body } => {
+ self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+ this.infer_expr(*body, expected)
+ })
+ .1
+ }
Expr::TryBlock { body } => {
- let _inner = self.infer_expr(*body, expected);
+ self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+ let _inner = this.infer_expr(*body, expected);
+ });
// FIXME should be std::result::Result<{inner}, _>
self.err_ty()
}
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
- let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+ let (_, inner_ty) =
+ self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+ this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty))
+ });
self.diverges = prev_diverges;
self.return_ty = prev_ret_ty;
TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
.intern(Interner)
}
- Expr::Loop { body, label } => {
- self.breakables.push(BreakableContext {
- may_break: false,
- coerce: CoerceMany::new(self.table.new_type_var()),
- label: label.map(|label| self.body[label].name.clone()),
- });
- self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-
- let ctxt = self.breakables.pop().expect("breakable stack broken");
+ &Expr::Loop { body, label } => {
+ let ty = self.table.new_type_var();
+ let (breaks, ()) =
+ self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| {
+ this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+ });
- if ctxt.may_break {
- self.diverges = Diverges::Maybe;
- ctxt.coerce.complete()
- } else {
- TyKind::Never.intern(Interner)
+ match breaks {
+ Some(breaks) => {
+ self.diverges = Diverges::Maybe;
+ breaks
+ }
+ None => TyKind::Never.intern(Interner),
}
}
- Expr::While { condition, body, label } => {
- self.breakables.push(BreakableContext {
- may_break: false,
- coerce: CoerceMany::new(self.err_ty()),
- label: label.map(|label| self.body[label].name.clone()),
+ &Expr::While { condition, body, label } => {
+ self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
+ this.infer_expr(
+ condition,
+ &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
+ );
+ this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
});
- self.infer_expr(
- *condition,
- &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
- );
- self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
- let _ctxt = self.breakables.pop().expect("breakable stack broken");
+
// the body may not run, so it diverging doesn't mean we diverge
self.diverges = Diverges::Maybe;
TyBuilder::unit()
}
- Expr::For { iterable, body, pat, label } => {
- let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
-
- self.breakables.push(BreakableContext {
- may_break: false,
- coerce: CoerceMany::new(self.err_ty()),
- label: label.map(|label| self.body[label].name.clone()),
- });
+ &Expr::For { iterable, body, pat, label } => {
+ let iterable_ty = self.infer_expr(iterable, &Expectation::none());
let pat_ty =
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
- self.infer_pat(*pat, &pat_ty, BindingMode::default());
+ self.infer_pat(pat, &pat_ty, BindingMode::default());
+ self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
+ this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+ });
- self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
- let _ctxt = self.breakables.pop().expect("breakable stack broken");
// the body may not run, so it diverging doesn't mean we diverge
self.diverges = Diverges::Maybe;
TyBuilder::unit()
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
- self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+ self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+ this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+ });
self.diverges = prev_diverges;
self.return_ty = prev_ret_ty;
let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty())
}
- Expr::Continue { .. } => TyKind::Never.intern(Interner),
- Expr::Break { expr, label } => {
- let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) {
- Some(ctxt) => {
- // avoiding the borrowck
- mem::replace(
- &mut ctxt.coerce,
- CoerceMany::new(self.result.standard_types.unknown.clone()),
- )
- }
- None => CoerceMany::new(self.result.standard_types.unknown.clone()),
+ Expr::Continue { label } => {
+ if let None = find_continuable(&mut self.breakables, label.as_ref()) {
+ self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
+ expr: tgt_expr,
+ is_break: false,
+ });
};
-
+ TyKind::Never.intern(Interner)
+ }
+ Expr::Break { expr, label } => {
let val_ty = if let Some(expr) = *expr {
self.infer_expr(expr, &Expectation::none())
} else {
TyBuilder::unit()
};
- // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
- coerce.coerce(self, *expr, &val_ty);
+ match find_breakable(&mut self.breakables, label.as_ref()) {
+ Some(ctxt) => {
+ // avoiding the borrowck
+ let mut coerce = mem::replace(
+ &mut ctxt.coerce,
+ CoerceMany::new(self.result.standard_types.unknown.clone()),
+ );
- if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
- ctxt.coerce = coerce;
- ctxt.may_break = true;
- } else {
- self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
- expr: tgt_expr,
- });
- };
+ // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
+ coerce.coerce(self, *expr, &val_ty);
+ let ctxt = find_breakable(&mut self.breakables, label.as_ref())
+ .expect("breakable stack changed during coercion");
+ ctxt.coerce = coerce;
+ ctxt.may_break = true;
+ }
+ None => {
+ self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
+ expr: tgt_expr,
+ is_break: true,
+ });
+ }
+ }
TyKind::Never.intern(Interner)
}
Expr::Return { expr } => {
None => self.table.new_float_var(),
},
},
- Expr::MacroStmts { tail, statements } => {
- self.infer_block(tgt_expr, statements, *tail, expected)
- }
Expr::Underscore => {
// Underscore expressions may only appear in assignee expressions,
// which are handled by `infer_assignee_expr()`, so any underscore
},
})
}
+
+ fn with_breakable_ctx<T>(
+ &mut self,
+ kind: BreakableKind,
+ ty: Ty,
+ label: Option<LabelId>,
+ cb: impl FnOnce(&mut Self) -> T,
+ ) -> (Option<Ty>, T) {
+ self.breakables.push({
+ let label = label.map(|label| self.body[label].name.clone());
+ BreakableContext { kind, may_break: false, coerce: CoerceMany::new(ty), label }
+ });
+ let res = cb(self);
+ let ctx = self.breakables.pop().expect("breakable stack broken");
+ (ctx.may_break.then(|| ctx.coerce.complete()), res)
+ }
}
--- /dev/null
+//! Type inhabitedness logic.
+use std::ops::ControlFlow::{self, Break, Continue};
+
+use chalk_ir::{
+ visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
+ DebruijnIndex,
+};
+use hir_def::{
+ adt::VariantData, attr::Attrs, type_ref::ConstScalar, visibility::Visibility, AdtId,
+ EnumVariantId, HasModule, Lookup, ModuleId, VariantId,
+};
+
+use crate::{
+ db::HirDatabase, Binders, ConcreteConst, Const, ConstValue, Interner, Substitution, Ty, TyKind,
+};
+
+/// Checks whether a type is visibly uninhabited from a particular module.
+pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool {
+ let mut uninhabited_from = UninhabitedFrom { target_mod, db };
+ let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
+ inhabitedness == BREAK_VISIBLY_UNINHABITED
+}
+
+/// Checks whether a variant is visibly uninhabited from a particular module.
+pub(crate) fn is_enum_variant_uninhabited_from(
+ variant: EnumVariantId,
+ subst: &Substitution,
+ target_mod: ModuleId,
+ db: &dyn HirDatabase,
+) -> bool {
+ let enum_data = db.enum_data(variant.parent);
+ let vars_attrs = db.variants_attrs(variant.parent);
+ let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate();
+
+ let mut uninhabited_from = UninhabitedFrom { target_mod, db };
+ let inhabitedness = uninhabited_from.visit_variant(
+ variant.into(),
+ &enum_data.variants[variant.local_id].variant_data,
+ subst,
+ &vars_attrs[variant.local_id],
+ is_local,
+ );
+ inhabitedness == BREAK_VISIBLY_UNINHABITED
+}
+
+struct UninhabitedFrom<'a> {
+ target_mod: ModuleId,
+ db: &'a dyn HirDatabase,
+}
+
+const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
+const BREAK_VISIBLY_UNINHABITED: ControlFlow<VisiblyUninhabited> = Break(VisiblyUninhabited);
+#[derive(PartialEq, Eq)]
+struct VisiblyUninhabited;
+
+impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
+ type BreakTy = VisiblyUninhabited;
+
+ fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = VisiblyUninhabited> {
+ self
+ }
+
+ fn visit_ty(
+ &mut self,
+ ty: &Ty,
+ outer_binder: DebruijnIndex,
+ ) -> ControlFlow<VisiblyUninhabited> {
+ match ty.kind(Interner) {
+ TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst),
+ TyKind::Never => BREAK_VISIBLY_UNINHABITED,
+ TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder),
+ TyKind::Array(item_ty, len) => match try_usize_const(len) {
+ Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
+ Some(1..) => item_ty.super_visit_with(self, outer_binder),
+ },
+
+ TyKind::Ref(..) | _ => CONTINUE_OPAQUELY_INHABITED,
+ }
+ }
+
+ fn interner(&self) -> Interner {
+ Interner
+ }
+}
+
+impl UninhabitedFrom<'_> {
+ fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
+ let attrs = self.db.attrs(adt.into());
+ let adt_non_exhaustive = attrs.by_key("non_exhaustive").exists();
+ let is_local = adt.module(self.db.upcast()).krate() == self.target_mod.krate();
+ if adt_non_exhaustive && !is_local {
+ return CONTINUE_OPAQUELY_INHABITED;
+ }
+
+ // An ADT is uninhabited iff all its variants uninhabited.
+ match adt {
+ // rustc: For now, `union`s are never considered uninhabited.
+ AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
+ AdtId::StructId(s) => {
+ let struct_data = self.db.struct_data(s);
+ self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local)
+ }
+ AdtId::EnumId(e) => {
+ let vars_attrs = self.db.variants_attrs(e);
+ let enum_data = self.db.enum_data(e);
+
+ for (local_id, enum_var) in enum_data.variants.iter() {
+ let variant_inhabitedness = self.visit_variant(
+ EnumVariantId { parent: e, local_id }.into(),
+ &enum_var.variant_data,
+ subst,
+ &vars_attrs[local_id],
+ is_local,
+ );
+ match variant_inhabitedness {
+ Break(VisiblyUninhabited) => continue,
+ Continue(()) => return CONTINUE_OPAQUELY_INHABITED,
+ }
+ }
+ BREAK_VISIBLY_UNINHABITED
+ }
+ }
+ }
+
+ fn visit_variant(
+ &mut self,
+ variant: VariantId,
+ variant_data: &VariantData,
+ subst: &Substitution,
+ attrs: &Attrs,
+ is_local: bool,
+ ) -> ControlFlow<VisiblyUninhabited> {
+ let non_exhaustive_field_list = attrs.by_key("non_exhaustive").exists();
+ if non_exhaustive_field_list && !is_local {
+ return CONTINUE_OPAQUELY_INHABITED;
+ }
+
+ let is_enum = matches!(variant, VariantId::EnumVariantId(..));
+ let field_tys = self.db.field_types(variant);
+ let field_vis = self.db.field_visibilities(variant);
+
+ for (fid, _) in variant_data.fields().iter() {
+ self.visit_field(field_vis[fid], &field_tys[fid], subst, is_enum)?;
+ }
+ CONTINUE_OPAQUELY_INHABITED
+ }
+
+ fn visit_field(
+ &mut self,
+ vis: Visibility,
+ ty: &Binders<Ty>,
+ subst: &Substitution,
+ is_enum: bool,
+ ) -> ControlFlow<VisiblyUninhabited> {
+ if is_enum || vis.is_visible_from(self.db.upcast(), self.target_mod) {
+ let ty = ty.clone().substitute(Interner, subst);
+ ty.visit_with(self, DebruijnIndex::INNERMOST)
+ } else {
+ CONTINUE_OPAQUELY_INHABITED
+ }
+ }
+}
+
+fn try_usize_const(c: &Const) -> Option<u128> {
+ let data = &c.data(Interner);
+ if data.ty.kind(Interner) != &TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)) {
+ return None;
+ }
+ match data.value {
+ ConstValue::Concrete(ConcreteConst { interned: ConstScalar::UInt(value) }) => Some(value),
+ _ => None,
+ }
+}
mod chalk_ext;
pub mod consteval;
mod infer;
+mod inhabitedness;
mod interner;
mod lower;
mod mapping;
//! Methods for lowering the HIR to types. There are two main cases here:
//!
//! - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
-//! type: The entry point for this is `Ty::from_hir`.
-//! - Building the type for an item: This happens through the `type_for_def` query.
+//! type: The entry point for this is `TyLoweringContext::lower_ty`.
+//! - Building the type for an item: This happens through the `ty` query.
//!
//! This usually involves resolving names, collecting generic arguments etc.
use std::{
consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
db::HirDatabase,
make_binders,
- mapping::ToChalk,
+ mapping::{from_chalk_trait_id, ToChalk},
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
utils::Generics,
utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
TypeRef::Macro(macro_call) => {
let (mut expander, recursion_start) = {
match RefMut::filter_map(self.expander.borrow_mut(), Option::as_mut) {
+ // There already is an expander here, this means we are already recursing
Ok(expander) => (expander, false),
+ // No expander was created yet, so we are at the start of the expansion recursion
+ // and therefore have to create an expander.
Err(expander) => (
RefMut::map(expander, |it| {
it.insert(Expander::new(
.exit(self.db.upcast(), mark);
Some(ty)
}
- _ => None,
+ _ => {
+ drop(expander);
+ None
+ }
}
};
+
+ // drop the expander, resetting it to pre-recursion state
if recursion_start {
*self.expander.borrow_mut() = None;
}
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
- QuantifiedWhereClauses::from_iter(
+ let bounds =
+ bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
+
+ let mut auto_traits = SmallVec::<[_; 8]>::new();
+ let mut regular_traits = SmallVec::<[_; 2]>::new();
+ let mut other_bounds = SmallVec::<[_; 8]>::new();
+ for bound in bounds {
+ if let Some(id) = bound.trait_id() {
+ if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
+ auto_traits.push(bound);
+ } else {
+ regular_traits.push(bound);
+ }
+ } else {
+ other_bounds.push(bound);
+ }
+ }
+
+ if regular_traits.len() > 1 {
+ return None;
+ }
+
+ auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap());
+ auto_traits.dedup();
+
+ Some(QuantifiedWhereClauses::from_iter(
Interner,
- bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
- )
+ regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
+ ))
});
- let bounds = crate::make_single_type_binders(bounds);
- TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
+
+ if let Some(bounds) = bounds {
+ let bounds = crate::make_single_type_binders(bounds);
+ TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
+ } else {
+ // FIXME: report error (additional non-auto traits)
+ TyKind::Error.intern(Interner)
+ }
}
fn lower_impl_trait(
!0..6 '1isize': isize
!0..6 '1isize': isize
!0..6 '1isize': isize
- !0..6 '1isize': isize
- !0..6 '1isize': isize
39..442 '{ ...!(); }': ()
73..94 'spam!(...am!())': {unknown}
100..119 'for _ ...!() {}': ()
!0..6 '1isize': isize
!0..6 '1isize': isize
!0..6 '1isize': isize
- !0..6 '1isize': isize
- !0..6 '1isize': isize
53..456 '{ ...!(); }': ()
87..108 'spam!(...am!())': {unknown}
114..133 'for _ ...!() {}': ()
}
"#,
expect![[r#"
- !0..8 'leta=();': ()
!3..4 'a': ()
!5..7 '()': ()
57..84 '{ ...); } }': ()
}
#[test]
-fn recurisve_macro_expanded_in_stmts() {
+fn recursive_macro_expanded_in_stmts() {
check_infer(
r#"
macro_rules! ng {
}
"#,
expect![[r#"
- !0..7 'leta=3;': ()
- !0..13 'ng!{[leta=3]}': ()
- !0..13 'ng!{[leta=]3}': ()
- !0..13 'ng!{[leta]=3}': ()
- !0..13 'ng!{[let]a=3}': ()
!3..4 'a': i32
!5..6 '3': i32
196..237 '{ ...= a; }': ()
"#,
expect![[r#"
!0..1 '1': i32
- !0..7 'mac!($)': ()
- !0..26 'macro_...>{1};}': ()
107..143 '{ ...!(); }': ()
129..130 'a': i32
"#]],
}
"#,
expect![[r#"
- !0..16 'let_a=...t_b=1;': ()
!3..5 '_a': i32
!6..7 '1': i32
!11..13 '_b': i32
#[test]
fn trailing_empty_macro() {
- cov_mark::check!(empty_macro_in_trailing_position_is_removed);
check_no_mismatches(
r#"
macro_rules! m2 {
expect![[r#"
569..573 'self': Box<[T], A>
602..634 '{ ... }': Vec<T, A>
- 612..628 'unimpl...ted!()': Vec<T, A>
648..761 '{ ...t]); }': ()
658..661 'vec': Vec<i32, Global>
664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
"#,
);
}
+
+#[test]
+fn nested_break() {
+ check_no_mismatches(
+ r#"
+fn func() {
+ let int = loop {
+ break 0;
+ break (break 0);
+ };
+}
+ "#,
+ );
+}
"#,
)
}
+
+#[test]
+fn dyn_multiple_auto_traits_in_different_order() {
+ check_no_mismatches(
+ r#"
+auto trait Send {}
+auto trait Sync {}
+
+fn f(t: &(dyn Sync + Send)) {}
+fn g(t: &(dyn Send + Sync)) {
+ f(t);
+}
+ "#,
+ );
+
+ check_no_mismatches(
+ r#"
+auto trait Send {}
+auto trait Sync {}
+trait T {}
+
+fn f(t: &(dyn T + Send + Sync)) {}
+fn g(t: &(dyn Sync + T + Send)) {
+ f(t);
+}
+ "#,
+ );
+
+ check_infer_with_mismatches(
+ r#"
+auto trait Send {}
+auto trait Sync {}
+trait T1 {}
+trait T2 {}
+
+fn f(t: &(dyn T1 + T2 + Send + Sync)) {}
+fn g(t: &(dyn Sync + T2 + T1 + Send)) {
+ f(t);
+}
+ "#,
+ expect![[r#"
+ 68..69 't': &{unknown}
+ 101..103 '{}': ()
+ 109..110 't': &{unknown}
+ 142..155 '{ f(t); }': ()
+ 148..149 'f': fn f(&{unknown})
+ 148..152 'f(t)': ()
+ 150..151 't': &{unknown}
+ "#]],
+ );
+
+ check_no_mismatches(
+ r#"
+auto trait Send {}
+auto trait Sync {}
+trait T {
+ type Proj: Send + Sync;
+}
+
+fn f(t: &(dyn T<Proj = ()> + Send + Sync)) {}
+fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
+ f(t);
+}
+ "#,
+ );
+}
+
+#[test]
+fn dyn_duplicate_auto_trait() {
+ check_no_mismatches(
+ r#"
+auto trait Send {}
+
+fn f(t: &(dyn Send + Send)) {}
+fn g(t: &(dyn Send)) {
+ f(t);
+}
+ "#,
+ );
+
+ check_no_mismatches(
+ r#"
+auto trait Send {}
+trait T {}
+
+fn f(t: &(dyn T + Send + Send)) {}
+fn g(t: &(dyn T + Send)) {
+ f(t);
+}
+ "#,
+ );
+}
#[derive(Debug)]
pub struct BreakOutsideOfLoop {
pub expr: InFile<AstPtr<ast::Expr>>,
+ pub is_break: bool,
}
#[derive(Debug)]
let field = source_map.field_syntax(*expr);
acc.push(NoSuchField { field }.into())
}
- hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
+ &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
let expr = source_map
- .expr_syntax(*expr)
+ .expr_syntax(expr)
.expect("break outside of loop in synthetic syntax");
- acc.push(BreakOutsideOfLoop { expr }.into())
+ acc.push(BreakOutsideOfLoop { expr, is_break }.into())
}
hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
match source_map.expr_syntax(*call_expr) {
) -> Option<InFile<ast::Expr>> {
let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
let expanded = db.parse_or_expand(macro_file)?;
-
- let res = match ast::MacroCall::cast(expanded.clone()) {
- Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?,
- _ => InFile::new(macro_file, ast::Expr::cast(expanded)?),
+ let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
+ match stmts.expr()? {
+ ast::Expr::MacroExpr(mac) => {
+ self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
+ }
+ expr => InFile::new(macro_file, expr),
+ }
+ } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
+ self.expand_expr(db, InFile::new(macro_file, call))?
+ } else {
+ InFile::new(macro_file, ast::Expr::cast(expanded)?)
};
+
Some(res)
}
--- /dev/null
+use syntax::ast::{self, AstNode};
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: convert_two_arm_bool_match_to_matches_macro
+//
+// Convert 2-arm match that evaluates to a boolean into the equivalent matches! invocation.
+//
+// ```
+// fn main() {
+// match scrutinee$0 {
+// Some(val) if val.cond() => true,
+// _ => false,
+// }
+// }
+// ```
+// ->
+// ```
+// fn main() {
+// matches!(scrutinee, Some(val) if val.cond())
+// }
+// ```
+pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
+ acc: &mut Assists,
+ ctx: &AssistContext<'_>,
+) -> Option<()> {
+ let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?;
+ let match_arm_list = match_expr.match_arm_list()?;
+ let mut arms = match_arm_list.arms();
+ let first_arm = arms.next()?;
+ let second_arm = arms.next()?;
+ if arms.next().is_some() {
+ cov_mark::hit!(non_two_arm_match);
+ return None;
+ }
+ let first_arm_expr = first_arm.expr();
+ let second_arm_expr = second_arm.expr();
+
+ let invert_matches = if is_bool_literal_expr(&first_arm_expr, true)
+ && is_bool_literal_expr(&second_arm_expr, false)
+ {
+ false
+ } else if is_bool_literal_expr(&first_arm_expr, false)
+ && is_bool_literal_expr(&second_arm_expr, true)
+ {
+ true
+ } else {
+ cov_mark::hit!(non_invert_bool_literal_arms);
+ return None;
+ };
+
+ let target_range = ctx.sema.original_range(match_expr.syntax()).range;
+ let expr = match_expr.expr()?;
+
+ acc.add(
+ AssistId("convert_two_arm_bool_match_to_matches_macro", AssistKind::RefactorRewrite),
+ "Convert to matches!",
+ target_range,
+ |builder| {
+ let mut arm_str = String::new();
+ if let Some(ref pat) = first_arm.pat() {
+ arm_str += &pat.to_string();
+ }
+ if let Some(ref guard) = first_arm.guard() {
+ arm_str += &format!(" {}", &guard.to_string());
+ }
+ if invert_matches {
+ builder.replace(target_range, format!("!matches!({}, {})", expr, arm_str));
+ } else {
+ builder.replace(target_range, format!("matches!({}, {})", expr, arm_str));
+ }
+ },
+ )
+}
+
+fn is_bool_literal_expr(expr: &Option<ast::Expr>, expect_bool: bool) -> bool {
+ if let Some(ast::Expr::Literal(lit)) = expr {
+ if let ast::LiteralKind::Bool(b) = lit.kind() {
+ return b == expect_bool;
+ }
+ }
+
+ return false;
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
+
+ use super::convert_two_arm_bool_match_to_matches_macro;
+
+ #[test]
+ fn not_applicable_outside_of_range_left() {
+ check_assist_not_applicable(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ $0 match a {
+ Some(_val) => true,
+ _ => false
+ }
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn not_applicable_non_two_arm_match() {
+ cov_mark::check!(non_two_arm_match);
+ check_assist_not_applicable(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ match a$0 {
+ Some(3) => true,
+ Some(4) => true,
+ _ => false
+ }
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn not_applicable_non_bool_literal_arms() {
+ cov_mark::check!(non_invert_bool_literal_arms);
+ check_assist_not_applicable(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ match a$0 {
+ Some(val) => val == 3,
+ _ => false
+ }
+}
+ "#,
+ );
+ }
+ #[test]
+ fn not_applicable_both_false_arms() {
+ cov_mark::check!(non_invert_bool_literal_arms);
+ check_assist_not_applicable(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ match a$0 {
+ Some(val) => false,
+ _ => false
+ }
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn not_applicable_both_true_arms() {
+ cov_mark::check!(non_invert_bool_literal_arms);
+ check_assist_not_applicable(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ match a$0 {
+ Some(val) => true,
+ _ => true
+ }
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn convert_simple_case() {
+ check_assist(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ match a$0 {
+ Some(_val) => true,
+ _ => false
+ }
+}
+"#,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ matches!(a, Some(_val))
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn convert_simple_invert_case() {
+ check_assist(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ match a$0 {
+ Some(_val) => false,
+ _ => true
+ }
+}
+"#,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ !matches!(a, Some(_val))
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn convert_with_guard_case() {
+ check_assist(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ match a$0 {
+ Some(val) if val > 3 => true,
+ _ => false
+ }
+}
+"#,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ matches!(a, Some(val) if val > 3)
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn convert_enum_match_cases() {
+ check_assist(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+enum X { A, B }
+
+fn foo(a: X) -> bool {
+ match a$0 {
+ X::A => true,
+ _ => false
+ }
+}
+"#,
+ r#"
+enum X { A, B }
+
+fn foo(a: X) -> bool {
+ matches!(a, X::A)
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn convert_target_simple() {
+ check_assist_target(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+fn foo(a: Option<u32>) -> bool {
+ match a$0 {
+ Some(val) => true,
+ _ => false
+ }
+}
+"#,
+ r#"match a {
+ Some(val) => true,
+ _ => false
+ }"#,
+ );
+ }
+
+ #[test]
+ fn convert_target_complex() {
+ check_assist_target(
+ convert_two_arm_bool_match_to_matches_macro,
+ r#"
+enum E { X, Y }
+
+fn main() {
+ match E::X$0 {
+ E::X => true,
+ _ => false,
+ }
+}
+"#,
+ "match E::X {
+ E::X => true,
+ _ => false,
+ }",
+ );
+ }
+}
});
}
- let indent = enum_ast.indent_level();
let generic_params = enum_ast
.generic_param_list()
.and_then(|known_generics| extract_generic_params(&known_generics, &field_list));
let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
let def =
create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
+
+ let enum_ast = variant.parent_enum();
+ let indent = enum_ast.indent_level();
def.reindent_to(indent);
- let start_offset = &variant.parent_enum().syntax().clone();
- ted::insert_all_raw(
- ted::Position::before(start_offset),
+ ted::insert_all(
+ ted::Position::before(enum_ast.syntax()),
vec![
def.syntax().clone().into(),
- make::tokens::whitespace(&format!("\n\n{}", indent)).into(),
+ make::tokens::whitespace(&format!("\n\n{indent}")).into(),
],
);
}
fn create_struct_def(
- variant_name: ast::Name,
+ name: ast::Name,
variant: &ast::Variant,
field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
generics: Option<ast::GenericParamList>,
field_list.into()
}
};
-
field_list.reindent_to(IndentLevel::single());
- let strukt = make::struct_(enum_vis, variant_name, generics, field_list).clone_for_update();
-
- // FIXME: Consider making this an actual function somewhere (like in `AttrsOwnerEdit`) after some deliberation
- let attrs_and_docs = |node: &SyntaxNode| {
- let mut select_next_ws = false;
- node.children_with_tokens().filter(move |child| {
- let accept = match child.kind() {
- ATTR | COMMENT => {
- select_next_ws = true;
- return true;
- }
- WHITESPACE if select_next_ws => true,
- _ => false,
- };
- select_next_ws = false;
-
- accept
- })
- };
+ let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
- // copy attributes & comments from variant
- let variant_attrs = attrs_and_docs(variant.syntax())
- .map(|tok| match tok.kind() {
- WHITESPACE => make::tokens::single_newline().into(),
- _ => tok,
- })
- .collect();
- ted::insert_all(ted::Position::first_child_of(strukt.syntax()), variant_attrs);
+ // take comments from variant
+ ted::insert_all(
+ ted::Position::first_child_of(strukt.syntax()),
+ take_all_comments(variant.syntax()),
+ );
// copy attributes from enum
ted::insert_all(
ted::Position::first_child_of(strukt.syntax()),
- enum_.attrs().map(|it| it.syntax().clone_for_update().into()).collect(),
+ enum_
+ .attrs()
+ .flat_map(|it| {
+ vec![it.syntax().clone_for_update().into(), make::tokens::single_newline().into()]
+ })
+ .collect(),
);
+
strukt
}
})
.unwrap_or_else(|| make::ty(&name.text()));
+ // change from a record to a tuple field list
let tuple_field = make::tuple_field(None, ty);
- let replacement = make::variant(
- name,
- Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))),
- )
- .clone_for_update();
- ted::replace(variant.syntax(), replacement.syntax());
+ let field_list = make::tuple_field_list(iter::once(tuple_field)).clone_for_update();
+ ted::replace(variant.field_list()?.syntax(), field_list.syntax());
+
+ // remove any ws after the name
+ if let Some(ws) = name
+ .syntax()
+ .siblings_with_tokens(syntax::Direction::Next)
+ .find_map(|tok| tok.into_token().filter(|tok| tok.kind() == WHITESPACE))
+ {
+ ted::remove(SyntaxElement::Token(ws));
+ }
+
Some(())
}
+// Note: this also detaches whitespace after comments,
+// since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
+// detaches nodes. If we only took the comments, we'd leave behind the old whitespace.
+fn take_all_comments(node: &SyntaxNode) -> Vec<SyntaxElement> {
+ let mut remove_next_ws = false;
+ node.children_with_tokens()
+ .filter_map(move |child| match child.kind() {
+ COMMENT => {
+ remove_next_ws = true;
+ child.detach();
+ Some(child)
+ }
+ WHITESPACE if remove_next_ws => {
+ remove_next_ws = false;
+ child.detach();
+ Some(make::tokens::single_newline().into())
+ }
+ _ => {
+ remove_next_ws = false;
+ None
+ }
+ })
+ .collect()
+}
+
fn apply_references(
insert_use_cfg: InsertUseConfig,
segment: ast::PathSegment,
fn test_extract_struct_carries_over_attributes() {
check_assist(
extract_struct_from_enum_variant,
- r#"#[derive(Debug)]
+ r#"
+#[derive(Debug)]
#[derive(Clone)]
enum Enum { Variant{ field: u32$0 } }"#,
- r#"#[derive(Debug)]#[derive(Clone)] struct Variant{ field: u32 }
+ r#"
+#[derive(Debug)]
+#[derive(Clone)]
+struct Variant{ field: u32 }
#[derive(Debug)]
#[derive(Clone)]
}
#[test]
- fn test_extract_struct_keep_comments_and_attrs_on_variant_struct() {
+ fn test_extract_struct_move_struct_variant_comments() {
check_assist(
extract_struct_from_enum_variant,
r#"
/* comment */
// other
/// comment
-#[attr]
struct One{
a: u32
}
enum A {
+ #[attr]
One(One)
}"#,
);
}
#[test]
- fn test_extract_struct_keep_comments_and_attrs_on_variant_tuple() {
+ fn test_extract_struct_move_tuple_variant_comments() {
check_assist(
extract_struct_from_enum_variant,
r#"
/* comment */
// other
/// comment
-#[attr]
struct One(u32, u32);
enum A {
+ #[attr]
One(One)
}"#,
);
--- /dev/null
+use ide_db::{
+ assists::{AssistId, AssistKind},
+ famous_defs::FamousDefs,
+};
+use syntax::{
+ ast::{self, make, Expr, HasArgList},
+ AstNode,
+};
+
+use crate::{AssistContext, Assists};
+
+// Assist: replace_or_with_or_else
+//
+// Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
+//
+// ```
+// # //- minicore:option
+// fn foo() {
+// let a = Some(1);
+// a.unwra$0p_or(2);
+// }
+// ```
+// ->
+// ```
+// fn foo() {
+// let a = Some(1);
+// a.unwrap_or_else(|| 2);
+// }
+// ```
+pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
+
+ let kind = is_option_or_result(call.receiver()?, ctx)?;
+
+ let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
+
+ let mut map_or = false;
+
+ let replace = match &*name.text() {
+ "unwrap_or" => "unwrap_or_else".to_string(),
+ "or" => "or_else".to_string(),
+ "ok_or" if kind == Kind::Option => "ok_or_else".to_string(),
+ "map_or" => {
+ map_or = true;
+ "map_or_else".to_string()
+ }
+ _ => return None,
+ };
+
+ let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
+ [] => make::arg_list(Vec::new()),
+ [first] => {
+ let param = into_closure(first);
+ make::arg_list(vec![param])
+ }
+ [first, second] if map_or => {
+ let param = into_closure(first);
+ make::arg_list(vec![param, second.clone()])
+ }
+ _ => return None,
+ };
+
+ acc.add(
+ AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite),
+ format!("Replace {} with {}", name.text(), replace),
+ call.syntax().text_range(),
+ |builder| {
+ builder.replace(name.syntax().text_range(), replace);
+ builder.replace_ast(arg_list, arg)
+ },
+ )
+}
+
+fn into_closure(param: &Expr) -> Expr {
+ (|| {
+ if let ast::Expr::CallExpr(call) = param {
+ if call.arg_list()?.args().count() == 0 {
+ Some(call.expr()?.clone())
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ })()
+ .unwrap_or_else(|| make::expr_closure(None, param.clone()))
+}
+
+// Assist: replace_or_else_with_or
+//
+// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
+//
+// ```
+// # //- minicore:option
+// fn foo() {
+// let a = Some(1);
+// a.unwra$0p_or_else(|| 2);
+// }
+// ```
+// ->
+// ```
+// fn foo() {
+// let a = Some(1);
+// a.unwrap_or(2);
+// }
+// ```
+pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
+
+ let kind = is_option_or_result(call.receiver()?, ctx)?;
+
+ let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
+
+ let mut map_or = false;
+ let replace = match &*name.text() {
+ "unwrap_or_else" => "unwrap_or".to_string(),
+ "or_else" => "or".to_string(),
+ "ok_or_else" if kind == Kind::Option => "ok_or".to_string(),
+ "map_or_else" => {
+ map_or = true;
+ "map_or".to_string()
+ }
+ _ => return None,
+ };
+
+ let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
+ [] => make::arg_list(Vec::new()),
+ [first] => {
+ let param = into_call(first);
+ make::arg_list(vec![param])
+ }
+ [first, second] if map_or => {
+ let param = into_call(first);
+ make::arg_list(vec![param, second.clone()])
+ }
+ _ => return None,
+ };
+
+ acc.add(
+ AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite),
+ format!("Replace {} with {}", name.text(), replace),
+ call.syntax().text_range(),
+ |builder| {
+ builder.replace(name.syntax().text_range(), replace);
+ builder.replace_ast(arg_list, arg)
+ },
+ )
+}
+
+fn into_call(param: &Expr) -> Expr {
+ (|| {
+ if let ast::Expr::ClosureExpr(closure) = param {
+ if closure.param_list()?.params().count() == 0 {
+ Some(closure.body()?.clone())
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ })()
+ .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())))
+}
+
+#[derive(PartialEq, Eq)]
+enum Kind {
+ Option,
+ Result,
+}
+
+fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<Kind> {
+ let ty = ctx.sema.type_of_expr(&receiver)?.adjusted().as_adt()?.as_enum()?;
+ let option_enum =
+ FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_option_Option();
+
+ if let Some(option_enum) = option_enum {
+ if ty == option_enum {
+ return Some(Kind::Option);
+ }
+ }
+
+ let result_enum =
+ FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_result_Result();
+
+ if let Some(result_enum) = result_enum {
+ if ty == result_enum {
+ return Some(Kind::Result);
+ }
+ }
+
+ None
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::{check_assist, check_assist_not_applicable};
+
+ use super::*;
+
+ #[test]
+ fn replace_or_with_or_else_simple() {
+ check_assist(
+ replace_or_with_or_else,
+ r#"
+//- minicore: option
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_$0or(2);
+}
+"#,
+ r#"
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_or_else(|| 2);
+}
+"#,
+ )
+ }
+
+ #[test]
+ fn replace_or_with_or_else_call() {
+ check_assist(
+ replace_or_with_or_else,
+ r#"
+//- minicore: option
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_$0or(x());
+}
+"#,
+ r#"
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_or_else(x);
+}
+"#,
+ )
+ }
+
+ #[test]
+ fn replace_or_with_or_else_block() {
+ check_assist(
+ replace_or_with_or_else,
+ r#"
+//- minicore: option
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_$0or({
+ let mut x = bar();
+ for i in 0..10 {
+ x += i;
+ }
+ x
+ });
+}
+"#,
+ r#"
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_or_else(|| {
+ let mut x = bar();
+ for i in 0..10 {
+ x += i;
+ }
+ x
+ });
+}
+"#,
+ )
+ }
+
+ #[test]
+ fn replace_or_else_with_or_simple() {
+ check_assist(
+ replace_or_else_with_or,
+ r#"
+//- minicore: option
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_$0or_else(|| 2);
+}
+"#,
+ r#"
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_or(2);
+}
+"#,
+ )
+ }
+
+ #[test]
+ fn replace_or_else_with_or_call() {
+ check_assist(
+ replace_or_else_with_or,
+ r#"
+//- minicore: option
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_$0or_else(x);
+}
+"#,
+ r#"
+fn foo() {
+ let foo = Some(1);
+ return foo.unwrap_or(x());
+}
+"#,
+ )
+ }
+
+ #[test]
+ fn replace_or_else_with_or_result() {
+ check_assist(
+ replace_or_else_with_or,
+ r#"
+//- minicore: result
+fn foo() {
+ let foo = Ok(1);
+ return foo.unwrap_$0or_else(x);
+}
+"#,
+ r#"
+fn foo() {
+ let foo = Ok(1);
+ return foo.unwrap_or(x());
+}
+"#,
+ )
+ }
+
+ #[test]
+ fn replace_or_else_with_or_map() {
+ check_assist(
+ replace_or_else_with_or,
+ r#"
+//- minicore: result
+fn foo() {
+ let foo = Ok("foo");
+ return foo.map$0_or_else(|| 42, |v| v.len());
+}
+"#,
+ r#"
+fn foo() {
+ let foo = Ok("foo");
+ return foo.map_or(42, |v| v.len());
+}
+"#,
+ )
+ }
+
+ #[test]
+ fn replace_or_else_with_or_not_applicable() {
+ check_assist_not_applicable(
+ replace_or_else_with_or,
+ r#"
+fn foo() {
+ let foo = Ok(1);
+ return foo.unwrap_$0or_else(x);
+}
+"#,
+ )
+ }
+}
+use hir::HirDisplay;
use syntax::{
- ast::{Expr, GenericArg},
+ ast::{Expr, GenericArg, GenericArgList},
ast::{LetStmt, Type::InferType},
AstNode, TextRange,
};
let initializer = let_stmt.initializer()?;
- let generic_args = match &initializer {
- Expr::MethodCallExpr(ce) => ce.generic_arg_list()?,
- Expr::CallExpr(ce) => {
- if let Expr::PathExpr(pe) = ce.expr()? {
- pe.path()?.segment()?.generic_arg_list()?
- } else {
- cov_mark::hit!(not_applicable_if_non_path_function_call);
- return None;
- }
- }
- _ => {
- cov_mark::hit!(not_applicable_if_non_function_call_initializer);
- return None;
- }
- };
+ let generic_args = generic_arg_list(&initializer)?;
// Find range of ::<_>
let colon2 = generic_args.coloncolon_token()?;
// An improvement would be to check that this is correctly part of the return value of the
// function call, or sub in the actual return type.
- let turbofish_type = &turbofish_args[0];
+ let returned_type = match ctx.sema.type_of_expr(&initializer) {
+ Some(returned_type) if !returned_type.original.contains_unknown() => {
+ let module = ctx.sema.scope(let_stmt.syntax())?.module();
+ returned_type.original.display_source_code(ctx.db(), module.into()).ok()?
+ }
+ _ => {
+ cov_mark::hit!(fallback_to_turbofish_type_if_type_info_not_available);
+ turbofish_args[0].to_string()
+ }
+ };
let initializer_start = initializer.syntax().text_range().start();
if ctx.offset() > turbofish_range.end() || ctx.offset() < initializer_start {
"Replace turbofish with explicit type",
TextRange::new(initializer_start, turbofish_range.end()),
|builder| {
- builder.insert(ident_range.end(), format!(": {}", turbofish_type));
+ builder.insert(ident_range.end(), format!(": {}", returned_type));
builder.delete(turbofish_range);
},
);
"Replace `_` with turbofish type",
turbofish_range,
|builder| {
- builder.replace(underscore_range, turbofish_type.to_string());
+ builder.replace(underscore_range, returned_type);
builder.delete(turbofish_range);
},
);
None
}
+fn generic_arg_list(expr: &Expr) -> Option<GenericArgList> {
+ match expr {
+ Expr::MethodCallExpr(expr) => expr.generic_arg_list(),
+ Expr::CallExpr(expr) => {
+ if let Expr::PathExpr(pe) = expr.expr()? {
+ pe.path()?.segment()?.generic_arg_list()
+ } else {
+ cov_mark::hit!(not_applicable_if_non_path_function_call);
+ return None;
+ }
+ }
+ Expr::AwaitExpr(expr) => generic_arg_list(&expr.expr()?),
+ Expr::TryExpr(expr) => generic_arg_list(&expr.expr()?),
+ _ => {
+ cov_mark::hit!(not_applicable_if_non_function_call_initializer);
+ None
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn replaces_turbofish_for_vec_string() {
+ cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available);
check_assist(
replace_turbofish_with_explicit_type,
r#"
#[test]
fn replaces_method_calls() {
// foo.make() is a method call which uses a different expr in the let initializer
+ cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available);
check_assist(
replace_turbofish_with_explicit_type,
r#"
fn main() {
let a = make$0::<Vec<String>, i32>();
}
+"#,
+ );
+ }
+
+ #[test]
+ fn replaces_turbofish_for_known_type() {
+ check_assist(
+ replace_turbofish_with_explicit_type,
+ r#"
+fn make<T>() -> T {}
+fn main() {
+ let a = make$0::<i32>();
+}
+"#,
+ r#"
+fn make<T>() -> T {}
+fn main() {
+ let a: i32 = make();
+}
+"#,
+ );
+ check_assist(
+ replace_turbofish_with_explicit_type,
+ r#"
+//- minicore: option
+fn make<T>() -> T {}
+fn main() {
+ let a = make$0::<Option<bool>>();
+}
+"#,
+ r#"
+fn make<T>() -> T {}
+fn main() {
+ let a: Option<bool> = make();
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn replaces_turbofish_not_same_type() {
+ check_assist(
+ replace_turbofish_with_explicit_type,
+ r#"
+//- minicore: option
+fn make<T>() -> Option<T> {}
+fn main() {
+ let a = make$0::<u128>();
+}
+"#,
+ r#"
+fn make<T>() -> Option<T> {}
+fn main() {
+ let a: Option<u128> = make();
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn replaces_turbofish_for_type_with_defaulted_generic_param() {
+ check_assist(
+ replace_turbofish_with_explicit_type,
+ r#"
+struct HasDefault<T, U = i32>(T, U);
+fn make<T>() -> HasDefault<T> {}
+fn main() {
+ let a = make$0::<bool>();
+}
+"#,
+ r#"
+struct HasDefault<T, U = i32>(T, U);
+fn make<T>() -> HasDefault<T> {}
+fn main() {
+ let a: HasDefault<bool> = make();
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn replaces_turbofish_try_await() {
+ check_assist(
+ replace_turbofish_with_explicit_type,
+ r#"
+//- minicore: option, future
+struct Fut<T>(T);
+impl<T> core::future::Future for Fut<T> {
+ type Output = Option<T>;
+}
+fn make<T>() -> Fut<T> {}
+fn main() {
+ let a = make$0::<bool>().await?;
+}
+"#,
+ r#"
+struct Fut<T>(T);
+impl<T> core::future::Future for Fut<T> {
+ type Output = Option<T>;
+}
+fn make<T>() -> Fut<T> {}
+fn main() {
+ let a: bool = make().await?;
+}
"#,
);
}
--- /dev/null
+use syntax::{
+ algo::neighbor,
+ ast::{self, edit::IndentLevel, make, AstNode},
+ ted::{self, Position},
+ Direction, SyntaxKind, T,
+};
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: unmerge_match_arm
+//
+// Splits the current match with a `|` pattern into two arms with identical bodies.
+//
+// ```
+// enum Action { Move { distance: u32 }, Stop }
+//
+// fn handle(action: Action) {
+// match action {
+// Action::Move(..) $0| Action::Stop => foo(),
+// }
+// }
+// ```
+// ->
+// ```
+// enum Action { Move { distance: u32 }, Stop }
+//
+// fn handle(action: Action) {
+// match action {
+// Action::Move(..) => foo(),
+// Action::Stop => foo(),
+// }
+// }
+// ```
+pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let pipe_token = ctx.find_token_syntax_at_offset(T![|])?;
+ let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update();
+ let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?;
+ let match_arm_body = match_arm.expr()?;
+
+ // We don't need to check for leading pipe because it is directly under `MatchArm`
+ // without `OrPat`.
+
+ let new_parent = match_arm.syntax().parent()?;
+ let old_parent_range = new_parent.text_range();
+
+ acc.add(
+ AssistId("unmerge_match_arm", AssistKind::RefactorRewrite),
+ "Unmerge match arm",
+ pipe_token.text_range(),
+ |edit| {
+ let pats_after = pipe_token
+ .siblings_with_tokens(Direction::Next)
+ .filter_map(|it| ast::Pat::cast(it.into_node()?));
+ // FIXME: We should add a leading pipe if the original arm has one.
+ let new_match_arm = make::match_arm(
+ pats_after,
+ match_arm.guard().and_then(|guard| guard.condition()),
+ match_arm_body,
+ )
+ .clone_for_update();
+
+ let mut pipe_index = pipe_token.index();
+ if pipe_token
+ .prev_sibling_or_token()
+ .map_or(false, |it| it.kind() == SyntaxKind::WHITESPACE)
+ {
+ pipe_index -= 1;
+ }
+ or_pat.syntax().splice_children(
+ pipe_index..or_pat.syntax().children_with_tokens().count(),
+ Vec::new(),
+ );
+
+ let mut insert_after_old_arm = Vec::new();
+
+ // A comma can be:
+ // - After the arm. In this case we always want to insert a comma after the newly
+ // inserted arm.
+ // - Missing after the arm, with no arms after. In this case we want to insert a
+ // comma before the newly inserted arm. It can not be necessary if there arm
+ // body is a block, but we don't bother to check that.
+ // - Missing after the arm with arms after, if the arm body is a block. In this case
+ // we don't want to insert a comma at all.
+ let has_comma_after =
+ std::iter::successors(match_arm.syntax().last_child_or_token(), |it| {
+ it.prev_sibling_or_token()
+ })
+ .map(|it| it.kind())
+ .skip_while(|it| it.is_trivia())
+ .next()
+ == Some(T![,]);
+ let has_arms_after = neighbor(&match_arm, Direction::Next).is_some();
+ if !has_comma_after && !has_arms_after {
+ insert_after_old_arm.push(make::token(T![,]).into());
+ }
+
+ let indent = IndentLevel::from_node(match_arm.syntax());
+ insert_after_old_arm.push(make::tokens::whitespace(&format!("\n{indent}")).into());
+
+ insert_after_old_arm.push(new_match_arm.syntax().clone().into());
+
+ ted::insert_all_raw(Position::after(match_arm.syntax()), insert_after_old_arm);
+
+ if has_comma_after {
+ ted::insert_raw(
+ Position::last_child_of(new_match_arm.syntax()),
+ make::token(T![,]),
+ );
+ }
+
+ edit.replace(old_parent_range, new_parent.to_string());
+ },
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::{check_assist, check_assist_not_applicable};
+
+ use super::*;
+
+ #[test]
+ fn unmerge_match_arm_single_pipe() {
+ check_assist(
+ unmerge_match_arm,
+ r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+ let x = X::A;
+ let y = match x {
+ X::A $0| X::B => { 1i32 }
+ X::C => { 2i32 }
+ };
+}
+"#,
+ r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+ let x = X::A;
+ let y = match x {
+ X::A => { 1i32 }
+ X::B => { 1i32 }
+ X::C => { 2i32 }
+ };
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unmerge_match_arm_guard() {
+ check_assist(
+ unmerge_match_arm,
+ r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+ let x = X::A;
+ let y = match x {
+ X::A $0| X::B if true => { 1i32 }
+ _ => { 2i32 }
+ };
+}
+"#,
+ r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+ let x = X::A;
+ let y = match x {
+ X::A if true => { 1i32 }
+ X::B if true => { 1i32 }
+ _ => { 2i32 }
+ };
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unmerge_match_arm_leading_pipe() {
+ check_assist_not_applicable(
+ unmerge_match_arm,
+ r#"
+
+fn main() {
+ let y = match 0 {
+ |$0 0 => { 1i32 }
+ 1 => { 2i32 }
+ };
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unmerge_match_arm_multiple_pipes() {
+ check_assist(
+ unmerge_match_arm,
+ r#"
+#[derive(Debug)]
+enum X { A, B, C, D, E }
+
+fn main() {
+ let x = X::A;
+ let y = match x {
+ X::A | X::B |$0 X::C | X::D => 1i32,
+ X::E => 2i32,
+ };
+}
+"#,
+ r#"
+#[derive(Debug)]
+enum X { A, B, C, D, E }
+
+fn main() {
+ let x = X::A;
+ let y = match x {
+ X::A | X::B => 1i32,
+ X::C | X::D => 1i32,
+ X::E => 2i32,
+ };
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unmerge_match_arm_inserts_comma_if_required() {
+ check_assist(
+ unmerge_match_arm,
+ r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+ let x = X::A;
+ let y = match x {
+ X::A $0| X::B => 1i32
+ };
+}
+"#,
+ r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+ let x = X::A;
+ let y = match x {
+ X::A => 1i32,
+ X::B => 1i32
+ };
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unmerge_match_arm_inserts_comma_if_had_after() {
+ check_assist(
+ unmerge_match_arm,
+ r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+ let x = X::A;
+ match x {
+ X::A $0| X::B => {},
+ }
+}
+"#,
+ r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+ let x = X::A;
+ match x {
+ X::A => {},
+ X::B => {},
+ }
+}
+"#,
+ );
+ }
+}
mod convert_let_else_to_match;
mod convert_tuple_struct_to_named_struct;
mod convert_to_guarded_return;
+ mod convert_two_arm_bool_match_to_matches_macro;
mod convert_while_to_loop;
mod destructure_tuple_binding;
mod expand_glob_import;
mod replace_try_expr_with_match;
mod replace_derive_with_manual_impl;
mod replace_if_let_with_match;
+ mod replace_or_with_or_else;
mod introduce_named_generic;
mod replace_let_with_if_let;
mod replace_qualified_name_with_use;
mod replace_string_with_char;
mod replace_turbofish_with_explicit_type;
mod split_import;
+ mod unmerge_match_arm;
mod sort_items;
mod toggle_ignore;
mod unmerge_use;
convert_let_else_to_match::convert_let_else_to_match,
convert_to_guarded_return::convert_to_guarded_return,
convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
+ convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
convert_while_to_loop::convert_while_to_loop,
destructure_tuple_binding::destructure_tuple_binding,
expand_glob_import::expand_glob_import,
replace_if_let_with_match::replace_if_let_with_match,
replace_if_let_with_match::replace_match_with_if_let,
replace_let_with_if_let::replace_let_with_if_let,
+ replace_or_with_or_else::replace_or_else_with_or,
+ replace_or_with_or_else::replace_or_with_or_else,
replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
replace_qualified_name_with_use::replace_qualified_name_with_use,
sort_items::sort_items,
split_import::split_import,
toggle_ignore::toggle_ignore,
+ unmerge_match_arm::unmerge_match_arm,
unmerge_use::unmerge_use,
unnecessary_async::unnecessary_async,
unwrap_block::unwrap_block,
)
}
+#[test]
+fn doctest_convert_two_arm_bool_match_to_matches_macro() {
+ check_doc_test(
+ "convert_two_arm_bool_match_to_matches_macro",
+ r#####"
+fn main() {
+ match scrutinee$0 {
+ Some(val) if val.cond() => true,
+ _ => false,
+ }
+}
+"#####,
+ r#####"
+fn main() {
+ matches!(scrutinee, Some(val) if val.cond())
+}
+"#####,
+ )
+}
+
#[test]
fn doctest_convert_while_to_loop() {
check_doc_test(
)
}
+#[test]
+fn doctest_replace_or_else_with_or() {
+ check_doc_test(
+ "replace_or_else_with_or",
+ r#####"
+//- minicore:option
+fn foo() {
+ let a = Some(1);
+ a.unwra$0p_or_else(|| 2);
+}
+"#####,
+ r#####"
+fn foo() {
+ let a = Some(1);
+ a.unwrap_or(2);
+}
+"#####,
+ )
+}
+
+#[test]
+fn doctest_replace_or_with_or_else() {
+ check_doc_test(
+ "replace_or_with_or_else",
+ r#####"
+//- minicore:option
+fn foo() {
+ let a = Some(1);
+ a.unwra$0p_or(2);
+}
+"#####,
+ r#####"
+fn foo() {
+ let a = Some(1);
+ a.unwrap_or_else(|| 2);
+}
+"#####,
+ )
+}
+
#[test]
fn doctest_replace_qualified_name_with_use() {
check_doc_test(
)
}
+#[test]
+fn doctest_unmerge_match_arm() {
+ check_doc_test(
+ "unmerge_match_arm",
+ r#####"
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+ match action {
+ Action::Move(..) $0| Action::Stop => foo(),
+ }
+}
+"#####,
+ r#####"
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+ match action {
+ Action::Move(..) => foo(),
+ Action::Stop => foo(),
+ }
+}
+"#####,
+ )
+}
+
#[test]
fn doctest_unmerge_use() {
check_doc_test(
}
}
- if let Some(ty) = innermost_ret_ty {
+ if let Some(ret_ty) = innermost_ret_ty {
add_keyword(
"return",
- match (in_block_expr, ty.is_unit()) {
- (true, true) => "return ;",
- (true, false) => "return;",
- (false, true) => "return $0",
- (false, false) => "return",
+ match (ret_ty.is_unit(), in_block_expr) {
+ (true, true) => {
+ cov_mark::hit!(return_unit_block);
+ "return;"
+ }
+ (true, false) => {
+ cov_mark::hit!(return_unit_no_block);
+ "return"
+ }
+ (false, true) => {
+ cov_mark::hit!(return_value_block);
+ "return $0;"
+ }
+ (false, false) => {
+ cov_mark::hit!(return_value_no_block);
+ "return $0"
+ }
},
);
}
//! Completion tests for expressions.
use expect_test::{expect, Expect};
-use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};
+use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE};
fn check(ra_fixture: &str, expect: Expect) {
let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture));
"#]],
);
}
+
+#[test]
+fn return_unit_block() {
+ cov_mark::check!(return_unit_block);
+ check_edit("return", r#"fn f() { if true { $0 } }"#, r#"fn f() { if true { return; } }"#);
+}
+
+#[test]
+fn return_unit_no_block() {
+ cov_mark::check!(return_unit_no_block);
+ check_edit(
+ "return",
+ r#"fn f() { match () { () => $0 } }"#,
+ r#"fn f() { match () { () => return } }"#,
+ );
+}
+
+#[test]
+fn return_value_block() {
+ cov_mark::check!(return_value_block);
+ check_edit(
+ "return",
+ r#"fn f() -> i32 { if true { $0 } }"#,
+ r#"fn f() -> i32 { if true { return $0; } }"#,
+ );
+}
+
+#[test]
+fn return_value_no_block() {
+ cov_mark::check!(return_value_no_block);
+ check_edit(
+ "return",
+ r#"fn f() -> i32 { match () { () => $0 } }"#,
+ r#"fn f() -> i32 { match () { () => return $0 } }"#,
+ );
+}
| ast::Expr::IndexExpr(_)
| ast::Expr::Literal(_)
| ast::Expr::MacroExpr(_)
- | ast::Expr::MacroStmts(_)
| ast::Expr::MethodCallExpr(_)
| ast::Expr::ParenExpr(_)
| ast::Expr::PathExpr(_)
ctx: &DiagnosticsContext<'_>,
d: &hir::BreakOutsideOfLoop,
) -> Diagnostic {
+ let construct = if d.is_break { "break" } else { "continue" };
Diagnostic::new(
"break-outside-of-loop",
- "break outside of loop",
+ format!("{construct} outside of loop"),
ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
)
}
use crate::tests::check_diagnostics;
#[test]
- fn break_outside_of_loop() {
+ fn outside_of_loop() {
check_diagnostics(
r#"
-fn foo() { break; }
- //^^^^^ error: break outside of loop
+fn foo() {
+ break;
+ //^^^^^ error: break outside of loop
+ break 'a;
+ //^^^^^^^^ error: break outside of loop
+ continue;
+ //^^^^^^^^ error: continue outside of loop
+ continue 'a;
+ //^^^^^^^^^^^ error: continue outside of loop
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn try_blocks_are_borders() {
+ check_diagnostics(
+ r#"
+fn foo() {
+ 'a: loop {
+ try {
+ break;
+ //^^^^^ error: break outside of loop
+ break 'a;
+ //^^^^^^^^ error: break outside of loop
+ continue;
+ //^^^^^^^^ error: continue outside of loop
+ continue 'a;
+ //^^^^^^^^^^^ error: continue outside of loop
+ };
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn async_blocks_are_borders() {
+ check_diagnostics(
+ r#"
+fn foo() {
+ 'a: loop {
+ try {
+ break;
+ //^^^^^ error: break outside of loop
+ break 'a;
+ //^^^^^^^^ error: break outside of loop
+ continue;
+ //^^^^^^^^ error: continue outside of loop
+ continue 'a;
+ //^^^^^^^^^^^ error: continue outside of loop
+ };
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn closures_are_borders() {
+ check_diagnostics(
+ r#"
+fn foo() {
+ 'a: loop {
+ try {
+ break;
+ //^^^^^ error: break outside of loop
+ break 'a;
+ //^^^^^^^^ error: break outside of loop
+ continue;
+ //^^^^^^^^ error: continue outside of loop
+ continue 'a;
+ //^^^^^^^^^^^ error: continue outside of loop
+ };
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn blocks_pass_through() {
+ check_diagnostics(
+ r#"
+fn foo() {
+ 'a: loop {
+ {
+ break;
+ break 'a;
+ continue;
+ continue 'a;
+ }
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn label_blocks() {
+ check_diagnostics(
+ r#"
+fn foo() {
+ 'a: {
+ break;
+ //^^^^^ error: break outside of loop
+ break 'a;
+ continue;
+ //^^^^^^^^ error: continue outside of loop
+ continue 'a;
+ //^^^^^^^^^^^ error: continue outside of loop
+ }
+}
"#,
);
}
);
}
+ mod rust_unstable {
+ use super::*;
+
+ #[test]
+ fn rfc_1872_exhaustive_patterns() {
+ check_diagnostics_no_bails(
+ r"
+//- minicore: option, result
+#![feature(exhaustive_patterns)]
+enum Void {}
+fn test() {
+ match None::<!> { None => () }
+ match Result::<u8, !>::Ok(2) { Ok(_) => () }
+ match Result::<u8, Void>::Ok(2) { Ok(_) => () }
+ match (2, loop {}) {}
+ match Result::<!, !>::Ok(loop {}) {}
+ match (&loop {}) {} // https://github.com/rust-lang/rust/issues/50642#issuecomment-388234919
+ // ^^^^^^^^^^ error: missing match arm: type `&!` is non-empty
+}",
+ );
+ }
+
+ #[test]
+ fn rfc_1872_private_uninhabitedness() {
+ check_diagnostics_no_bails(
+ r"
+//- minicore: option
+//- /lib.rs crate:lib
+#![feature(exhaustive_patterns)]
+pub struct PrivatelyUninhabited { private_field: Void }
+enum Void {}
+fn test_local(x: Option<PrivatelyUninhabited>) {
+ match x {}
+} // ^ error: missing match arm: `None` not covered
+//- /main.rs crate:main deps:lib
+#![feature(exhaustive_patterns)]
+fn test(x: Option<lib::PrivatelyUninhabited>) {
+ match x {}
+ // ^ error: missing match arm: `None` and `Some(_)` not covered
+}",
+ );
+ }
+ }
+
mod false_negatives {
//! The implementation of match checking here is a work in progress. As we roll this out, we
//! prefer false negatives to false positives (ideally there would be no false positives). This
pub struct Box<T> {}
trait Display {}
-trait Sync {}
+auto trait Sync {}
fn main() {
// The block expression wrapping disables the constructor hint hiding logic
match mode {
Mode::Use => {}
Mode::Type => {
+ // test typepathfn_with_coloncolon
+ // type F = Start::(Middle) -> (Middle)::End;
+ if p.at(T![::]) && p.nth_at(2, T!['(']) {
+ p.bump(T![::]);
+ }
// test path_fn_trait_args
// type F = Box<Fn(i32) -> ()>;
if p.at(T!['(']) {
use self::SyntaxKind::*;
impl SyntaxKind {
pub fn is_keyword(self) -> bool {
- match self {
- AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW
- | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW
- | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
- | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW
- | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW
- | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW
- | RAW_KW | MACRO_RULES_KW => true,
- _ => false,
- }
+ matches!(
+ self,
+ AS_KW
+ | ASYNC_KW
+ | AWAIT_KW
+ | BOX_KW
+ | BREAK_KW
+ | CONST_KW
+ | CONTINUE_KW
+ | CRATE_KW
+ | DYN_KW
+ | ELSE_KW
+ | ENUM_KW
+ | EXTERN_KW
+ | FALSE_KW
+ | FN_KW
+ | FOR_KW
+ | IF_KW
+ | IMPL_KW
+ | IN_KW
+ | LET_KW
+ | LOOP_KW
+ | MACRO_KW
+ | MATCH_KW
+ | MOD_KW
+ | MOVE_KW
+ | MUT_KW
+ | PUB_KW
+ | REF_KW
+ | RETURN_KW
+ | SELF_KW
+ | SELF_TYPE_KW
+ | STATIC_KW
+ | STRUCT_KW
+ | SUPER_KW
+ | TRAIT_KW
+ | TRUE_KW
+ | TRY_KW
+ | TYPE_KW
+ | UNSAFE_KW
+ | USE_KW
+ | WHERE_KW
+ | WHILE_KW
+ | YIELD_KW
+ | AUTO_KW
+ | DEFAULT_KW
+ | EXISTENTIAL_KW
+ | UNION_KW
+ | RAW_KW
+ | MACRO_RULES_KW
+ )
}
pub fn is_punct(self) -> bool {
- match self {
- SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK
- | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS
- | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON
- | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ
- | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2
- | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true,
- _ => false,
- }
+ matches!(
+ self,
+ SEMICOLON
+ | COMMA
+ | L_PAREN
+ | R_PAREN
+ | L_CURLY
+ | R_CURLY
+ | L_BRACK
+ | R_BRACK
+ | L_ANGLE
+ | R_ANGLE
+ | AT
+ | POUND
+ | TILDE
+ | QUESTION
+ | DOLLAR
+ | AMP
+ | PIPE
+ | PLUS
+ | STAR
+ | SLASH
+ | CARET
+ | PERCENT
+ | UNDERSCORE
+ | DOT
+ | DOT2
+ | DOT3
+ | DOT2EQ
+ | COLON
+ | COLON2
+ | EQ
+ | EQ2
+ | FAT_ARROW
+ | BANG
+ | NEQ
+ | MINUS
+ | THIN_ARROW
+ | LTEQ
+ | GTEQ
+ | PLUSEQ
+ | MINUSEQ
+ | PIPEEQ
+ | AMPEQ
+ | CARETEQ
+ | SLASHEQ
+ | STAREQ
+ | PERCENTEQ
+ | AMP2
+ | PIPE2
+ | SHL
+ | SHR
+ | SHLEQ
+ | SHREQ
+ )
}
pub fn is_literal(self) -> bool {
- match self {
- INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING => true,
- _ => false,
- }
+ matches!(self, INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING)
}
pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
let kw = match ident {
--- /dev/null
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "F"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Start"
+ COLON2 "::"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Middle"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PAREN_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Middle"
+ R_PAREN ")"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "End"
+ SEMICOLON ";"
+ WHITESPACE "\n"
--- /dev/null
+type F = Start::(Middle) -> (Middle)::End;
pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
+ pub(crate) proc_macros_loaded: bool,
}
impl std::panic::UnwindSafe for GlobalStateSnapshot {}
check_fixes: Arc::clone(&self.diagnostics.check_fixes),
mem_docs: self.mem_docs.clone(),
semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
+ proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(),
}
}
let text = snap.analysis.file_text(file_id)?;
let line_index = snap.file_line_index(file_id)?;
- let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
+ let mut highlight_config = snap.config.highlighting_config();
+ // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
+ highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
+
+ let highlights = snap.analysis.highlight(highlight_config, file_id)?;
let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
// Unconditionally cache the tokens
let text = snap.analysis.file_text(file_id)?;
let line_index = snap.file_line_index(file_id)?;
- let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
+ let mut highlight_config = snap.config.highlighting_config();
+ // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
+ highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
+
+ let highlights = snap.analysis.highlight(highlight_config, file_id)?;
let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
let mut cache = snap.semantic_tokens_cache.lock();
error
})
})
- .collect();
- }
+ .collect()
+ };
}
let watch = match files_config.watcher {
| Literal
| LoopExpr
| MacroExpr
-| MacroStmts
| MatchExpr
| MethodCallExpr
| ParenExpr
Literal(Literal),
LoopExpr(LoopExpr),
MacroExpr(MacroExpr),
- MacroStmts(MacroStmts),
MatchExpr(MatchExpr),
MethodCallExpr(MethodCallExpr),
ParenExpr(ParenExpr),
}
impl AstNode for GenericArg {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG => true,
- _ => false,
- }
+ matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
}
impl AstNode for Type {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- ARRAY_TYPE | DYN_TRAIT_TYPE | FN_PTR_TYPE | FOR_TYPE | IMPL_TRAIT_TYPE | INFER_TYPE
- | MACRO_TYPE | NEVER_TYPE | PAREN_TYPE | PATH_TYPE | PTR_TYPE | REF_TYPE
- | SLICE_TYPE | TUPLE_TYPE => true,
- _ => false,
- }
+ matches!(
+ kind,
+ ARRAY_TYPE
+ | DYN_TRAIT_TYPE
+ | FN_PTR_TYPE
+ | FOR_TYPE
+ | IMPL_TRAIT_TYPE
+ | INFER_TYPE
+ | MACRO_TYPE
+ | NEVER_TYPE
+ | PAREN_TYPE
+ | PATH_TYPE
+ | PTR_TYPE
+ | REF_TYPE
+ | SLICE_TYPE
+ | TUPLE_TYPE
+ )
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
impl From<MacroExpr> for Expr {
fn from(node: MacroExpr) -> Expr { Expr::MacroExpr(node) }
}
-impl From<MacroStmts> for Expr {
- fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
-}
impl From<MatchExpr> for Expr {
fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
}
}
impl AstNode for Expr {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
- | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR
- | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_EXPR | MACRO_STMTS | MATCH_EXPR
- | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
- | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
- | YIELD_EXPR | LET_EXPR | UNDERSCORE_EXPR => true,
- _ => false,
- }
+ matches!(
+ kind,
+ ARRAY_EXPR
+ | AWAIT_EXPR
+ | BIN_EXPR
+ | BLOCK_EXPR
+ | BOX_EXPR
+ | BREAK_EXPR
+ | CALL_EXPR
+ | CAST_EXPR
+ | CLOSURE_EXPR
+ | CONTINUE_EXPR
+ | FIELD_EXPR
+ | FOR_EXPR
+ | IF_EXPR
+ | INDEX_EXPR
+ | LITERAL
+ | LOOP_EXPR
+ | MACRO_EXPR
+ | MATCH_EXPR
+ | METHOD_CALL_EXPR
+ | PAREN_EXPR
+ | PATH_EXPR
+ | PREFIX_EXPR
+ | RANGE_EXPR
+ | RECORD_EXPR
+ | REF_EXPR
+ | RETURN_EXPR
+ | TRY_EXPR
+ | TUPLE_EXPR
+ | WHILE_EXPR
+ | YIELD_EXPR
+ | LET_EXPR
+ | UNDERSCORE_EXPR
+ )
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
LITERAL => Expr::Literal(Literal { syntax }),
LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }),
- MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
Expr::Literal(it) => &it.syntax,
Expr::LoopExpr(it) => &it.syntax,
Expr::MacroExpr(it) => &it.syntax,
- Expr::MacroStmts(it) => &it.syntax,
Expr::MatchExpr(it) => &it.syntax,
Expr::MethodCallExpr(it) => &it.syntax,
Expr::ParenExpr(it) => &it.syntax,
}
impl AstNode for Item {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES
- | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
- _ => false,
- }
+ matches!(
+ kind,
+ CONST
+ | ENUM
+ | EXTERN_BLOCK
+ | EXTERN_CRATE
+ | FN
+ | IMPL
+ | MACRO_CALL
+ | MACRO_RULES
+ | MACRO_DEF
+ | MODULE
+ | STATIC
+ | STRUCT
+ | TRAIT
+ | TYPE_ALIAS
+ | UNION
+ | USE
+ )
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
}
impl AstNode for Pat {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- IDENT_PAT | BOX_PAT | REST_PAT | LITERAL_PAT | MACRO_PAT | OR_PAT | PAREN_PAT
- | PATH_PAT | WILDCARD_PAT | RANGE_PAT | RECORD_PAT | REF_PAT | SLICE_PAT
- | TUPLE_PAT | TUPLE_STRUCT_PAT | CONST_BLOCK_PAT => true,
- _ => false,
- }
+ matches!(
+ kind,
+ IDENT_PAT
+ | BOX_PAT
+ | REST_PAT
+ | LITERAL_PAT
+ | MACRO_PAT
+ | OR_PAT
+ | PAREN_PAT
+ | PATH_PAT
+ | WILDCARD_PAT
+ | RANGE_PAT
+ | RECORD_PAT
+ | REF_PAT
+ | SLICE_PAT
+ | TUPLE_PAT
+ | TUPLE_STRUCT_PAT
+ | CONST_BLOCK_PAT
+ )
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) }
}
impl AstNode for FieldList {
- fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- RECORD_FIELD_LIST | TUPLE_FIELD_LIST => true,
- _ => false,
- }
- }
+ fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) }
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }),
fn from(node: Union) -> Adt { Adt::Union(node) }
}
impl AstNode for Adt {
- fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- ENUM | STRUCT | UNION => true,
- _ => false,
- }
- }
+ fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) }
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
ENUM => Adt::Enum(Enum { syntax }),
fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) }
}
impl AstNode for AssocItem {
- fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- CONST | FN | MACRO_CALL | TYPE_ALIAS => true,
- _ => false,
- }
- }
+ fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) }
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
CONST => AssocItem::Const(Const { syntax }),
fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) }
}
impl AstNode for ExternItem {
- fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- FN | MACRO_CALL | STATIC | TYPE_ALIAS => true,
- _ => false,
- }
- }
+ fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) }
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
FN => ExternItem::Fn(Fn { syntax }),
}
impl AstNode for GenericParam {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM => true,
- _ => false,
- }
+ matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
}
}
impl AstNode for AnyHasArgList {
- fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- CALL_EXPR | METHOD_CALL_EXPR => true,
- _ => false,
- }
- }
+ fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CALL_EXPR | METHOD_CALL_EXPR) }
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| AnyHasArgList { syntax })
}
}
impl AstNode for AnyHasAttrs {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
+ matches!(
+ kind,
MACRO_CALL
- | SOURCE_FILE
- | CONST
- | ENUM
- | EXTERN_BLOCK
- | EXTERN_CRATE
- | FN
- | IMPL
- | MACRO_RULES
- | MACRO_DEF
- | MODULE
- | STATIC
- | STRUCT
- | TRAIT
- | TYPE_ALIAS
- | UNION
- | USE
- | ITEM_LIST
- | BLOCK_EXPR
- | SELF_PARAM
- | PARAM
- | RECORD_FIELD
- | TUPLE_FIELD
- | VARIANT
- | ASSOC_ITEM_LIST
- | EXTERN_ITEM_LIST
- | CONST_PARAM
- | LIFETIME_PARAM
- | TYPE_PARAM
- | LET_STMT
- | ARRAY_EXPR
- | AWAIT_EXPR
- | BIN_EXPR
- | BOX_EXPR
- | BREAK_EXPR
- | CALL_EXPR
- | CAST_EXPR
- | CLOSURE_EXPR
- | CONTINUE_EXPR
- | FIELD_EXPR
- | FOR_EXPR
- | IF_EXPR
- | INDEX_EXPR
- | LITERAL
- | LOOP_EXPR
- | MATCH_EXPR
- | METHOD_CALL_EXPR
- | PAREN_EXPR
- | PATH_EXPR
- | PREFIX_EXPR
- | RANGE_EXPR
- | REF_EXPR
- | RETURN_EXPR
- | TRY_EXPR
- | TUPLE_EXPR
- | WHILE_EXPR
- | YIELD_EXPR
- | LET_EXPR
- | UNDERSCORE_EXPR
- | STMT_LIST
- | RECORD_EXPR_FIELD_LIST
- | RECORD_EXPR_FIELD
- | MATCH_ARM_LIST
- | MATCH_ARM
- | IDENT_PAT
- | REST_PAT
- | RECORD_PAT_FIELD => true,
- _ => false,
- }
+ | SOURCE_FILE
+ | CONST
+ | ENUM
+ | EXTERN_BLOCK
+ | EXTERN_CRATE
+ | FN
+ | IMPL
+ | MACRO_RULES
+ | MACRO_DEF
+ | MODULE
+ | STATIC
+ | STRUCT
+ | TRAIT
+ | TYPE_ALIAS
+ | UNION
+ | USE
+ | ITEM_LIST
+ | BLOCK_EXPR
+ | SELF_PARAM
+ | PARAM
+ | RECORD_FIELD
+ | TUPLE_FIELD
+ | VARIANT
+ | ASSOC_ITEM_LIST
+ | EXTERN_ITEM_LIST
+ | CONST_PARAM
+ | LIFETIME_PARAM
+ | TYPE_PARAM
+ | LET_STMT
+ | ARRAY_EXPR
+ | AWAIT_EXPR
+ | BIN_EXPR
+ | BOX_EXPR
+ | BREAK_EXPR
+ | CALL_EXPR
+ | CAST_EXPR
+ | CLOSURE_EXPR
+ | CONTINUE_EXPR
+ | FIELD_EXPR
+ | FOR_EXPR
+ | IF_EXPR
+ | INDEX_EXPR
+ | LITERAL
+ | LOOP_EXPR
+ | MATCH_EXPR
+ | METHOD_CALL_EXPR
+ | PAREN_EXPR
+ | PATH_EXPR
+ | PREFIX_EXPR
+ | RANGE_EXPR
+ | REF_EXPR
+ | RETURN_EXPR
+ | TRY_EXPR
+ | TUPLE_EXPR
+ | WHILE_EXPR
+ | YIELD_EXPR
+ | LET_EXPR
+ | UNDERSCORE_EXPR
+ | STMT_LIST
+ | RECORD_EXPR_FIELD_LIST
+ | RECORD_EXPR_FIELD
+ | MATCH_ARM_LIST
+ | MATCH_ARM
+ | IDENT_PAT
+ | REST_PAT
+ | RECORD_PAT_FIELD
+ )
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| AnyHasAttrs { syntax })
}
impl AstNode for AnyHasDocComments {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- MACRO_CALL | SOURCE_FILE | CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL
- | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION
- | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => true,
- _ => false,
- }
+ matches!(
+ kind,
+ MACRO_CALL
+ | SOURCE_FILE
+ | CONST
+ | ENUM
+ | EXTERN_BLOCK
+ | EXTERN_CRATE
+ | FN
+ | IMPL
+ | MACRO_RULES
+ | MACRO_DEF
+ | MODULE
+ | STATIC
+ | STRUCT
+ | TRAIT
+ | TYPE_ALIAS
+ | UNION
+ | USE
+ | RECORD_FIELD
+ | TUPLE_FIELD
+ | VARIANT
+ )
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| AnyHasDocComments { syntax })
}
impl AstNode for AnyHasGenericParams {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION => true,
- _ => false,
- }
+ matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| AnyHasGenericParams { syntax })
}
}
impl AstNode for AnyHasLoopBody {
- fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- FOR_EXPR | LOOP_EXPR | WHILE_EXPR => true,
- _ => false,
- }
- }
+ fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FOR_EXPR | LOOP_EXPR | WHILE_EXPR) }
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| AnyHasLoopBody { syntax })
}
}
}
impl AstNode for AnyHasModuleItem {
- fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => true,
- _ => false,
- }
- }
+ fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, MACRO_ITEMS | SOURCE_FILE | ITEM_LIST) }
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| AnyHasModuleItem { syntax })
}
}
impl AstNode for AnyHasName {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- CONST | ENUM | FN | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT
- | TYPE_ALIAS | UNION | RENAME | SELF_PARAM | RECORD_FIELD | VARIANT | CONST_PARAM
- | TYPE_PARAM | IDENT_PAT => true,
- _ => false,
- }
+ matches!(
+ kind,
+ CONST
+ | ENUM
+ | FN
+ | MACRO_RULES
+ | MACRO_DEF
+ | MODULE
+ | STATIC
+ | STRUCT
+ | TRAIT
+ | TYPE_ALIAS
+ | UNION
+ | RENAME
+ | SELF_PARAM
+ | RECORD_FIELD
+ | VARIANT
+ | CONST_PARAM
+ | TYPE_PARAM
+ | IDENT_PAT
+ )
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| AnyHasName { syntax })
}
impl AstNode for AnyHasTypeBounds {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED => true,
- _ => false,
- }
+ matches!(
+ kind,
+ ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED
+ )
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| AnyHasTypeBounds { syntax })
}
impl AstNode for AnyHasVisibility {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- CONST | ENUM | EXTERN_CRATE | FN | IMPL | MACRO_RULES | MACRO_DEF | MODULE | STATIC
- | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => {
- true
- }
- _ => false,
- }
+ matches!(
+ kind,
+ CONST
+ | ENUM
+ | EXTERN_CRATE
+ | FN
+ | IMPL
+ | MACRO_RULES
+ | MACRO_DEF
+ | MODULE
+ | STATIC
+ | STRUCT
+ | TRAIT
+ | TYPE_ALIAS
+ | UNION
+ | USE
+ | RECORD_FIELD
+ | TUPLE_FIELD
+ | VARIANT
+ )
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| AnyHasVisibility { syntax })
return from_text(&name.text());
fn from_text(text: &str) -> ast::IdentPat {
- ast_from_text(&format!("fn f({}: ())", text))
+ ast_from_text(&format!("fn f({text}: ())"))
}
}
pub fn ident_path(ident: &str) -> ast::Path {
expr_from_text("todo!()")
}
pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr {
- expr_from_text(&format!("{}::default()", ty))
+ expr_from_text(&format!("{ty}::default()"))
}
pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr {
- expr_from_text(&format!("{}::new()", ty))
+ expr_from_text(&format!("{ty}::new()"))
}
pub fn zero_number() -> ast::Expr {
ty_path(ident_path("bool"))
}
pub fn ty_option(t: ast::Type) -> ast::Type {
- ty_from_text(&format!("Option<{}>", t))
+ ty_from_text(&format!("Option<{t}>"))
}
pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type {
- ty_from_text(&format!("Result<{}, {}>", t, e))
+ ty_from_text(&format!("Result<{t}, {e}>"))
}
}
-pub fn name(text: &str) -> ast::Name {
- ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text))
+pub fn name(name: &str) -> ast::Name {
+ let raw_escape = raw_ident_esc(name);
+ ast_from_text(&format!("mod {raw_escape}{name};"))
}
-pub fn name_ref(text: &str) -> ast::NameRef {
- ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text))
+pub fn name_ref(name_ref: &str) -> ast::NameRef {
+ let raw_escape = raw_ident_esc(name_ref);
+ ast_from_text(&format!("fn f() {{ {raw_escape}{name_ref}; }}"))
}
fn raw_ident_esc(ident: &str) -> &'static str {
let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some();
let mut text = text;
let tmp;
if never!(!text.starts_with('\'')) {
- tmp = format!("'{}", text);
+ tmp = format!("'{text}");
text = &tmp;
}
- ast_from_text(&format!("fn f<{}>() {{ }}", text))
+ ast_from_text(&format!("fn f<{text}>() {{ }}"))
}
// FIXME: replace stringly-typed constructor with a family of typed ctors, a-la
contents.push(',');
}
- ty_from_text(&format!("({})", contents))
+ ty_from_text(&format!("({contents})"))
}
pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type {
- ty_from_text(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) })
+ ty_from_text(&if exclusive { format!("&mut {target}") } else { format!("&{target}") })
}
pub fn ty_path(path: ast::Path) -> ast::Type {
ty_from_text(&path.to_string())
}
fn ty_from_text(text: &str) -> ast::Type {
- ast_from_text(&format!("type _T = {};", text))
+ ast_from_text(&format!("type _T = {text};"))
}
pub fn assoc_item_list() -> ast::AssocItemList {
Some(params) => params.to_string(),
None => String::new(),
};
- ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params))
+ ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}"))
}
pub fn impl_trait(
ty_params: Option<ast::GenericParamList>,
) -> ast::Impl {
let ty_params = ty_params.map_or_else(String::new, |params| params.to_string());
- ast_from_text(&format!("impl{2} {} for {}{2} {{}}", trait_, ty, ty_params))
+ ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}"))
}
pub(crate) fn generic_arg_list() -> ast::GenericArgList {
}
pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
- ast_from_text(&format!("type __ = {};", name_ref))
+ ast_from_text(&format!("type __ = {name_ref};"))
}
pub fn path_segment_ty(type_ref: ast::Type, trait_ref: Option<ast::PathType>) -> ast::PathSegment {
let text = match trait_ref {
- Some(trait_ref) => format!("fn f(x: <{} as {}>) {{}}", type_ref, trait_ref),
- None => format!("fn f(x: <{}>) {{}}", type_ref),
+ Some(trait_ref) => format!("fn f(x: <{type_ref} as {trait_ref}>) {{}}"),
+ None => format!("fn f(x: <{type_ref}>) {{}}"),
};
ast_from_text(&text)
}
}
pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
- ast_from_text(&format!("type __ = {};", segment))
+ ast_from_text(&format!("type __ = {segment};"))
}
pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
- ast_from_text(&format!("{}::{}", qual, segment))
+ ast_from_text(&format!("{qual}::{segment}"))
}
// FIXME: path concatenation operation doesn't make sense as AST op.
pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path {
- ast_from_text(&format!("type __ = {}::{};", first, second))
+ ast_from_text(&format!("type __ = {first}::{second};"))
}
pub fn path_from_segments(
) -> ast::Path {
let segments = segments.into_iter().map(|it| it.syntax().clone()).join("::");
ast_from_text(&if is_abs {
- format!("fn f(x: ::{}) {{}}", segments)
+ format!("fn f(x: ::{segments}) {{}}")
} else {
- format!("fn f(x: {}) {{}}", segments)
+ format!("fn f(x: {segments}) {{}}")
})
}
pub fn join_paths(paths: impl IntoIterator<Item = ast::Path>) -> ast::Path {
let paths = paths.into_iter().map(|it| it.syntax().clone()).join("::");
- ast_from_text(&format!("type __ = {};", paths))
+ ast_from_text(&format!("type __ = {paths};"))
}
// FIXME: should not be pub
pub fn path_from_text(text: &str) -> ast::Path {
- ast_from_text(&format!("fn main() {{ let test = {}; }}", text))
+ ast_from_text(&format!("fn main() {{ let test = {text}; }}"))
}
pub fn use_tree_glob() -> ast::UseTree {
let mut buf = "use ".to_string();
buf += &path.syntax().to_string();
if let Some(use_tree_list) = use_tree_list {
- format_to!(buf, "::{}", use_tree_list);
+ format_to!(buf, "::{use_tree_list}");
}
if add_star {
buf += "::*";
}
if let Some(alias) = alias {
- format_to!(buf, " {}", alias);
+ format_to!(buf, " {alias}");
}
ast_from_text(&buf)
}
pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast::UseTreeList {
let use_trees = use_trees.into_iter().map(|it| it.syntax().clone()).join(", ");
- ast_from_text(&format!("use {{{}}};", use_trees))
+ ast_from_text(&format!("use {{{use_trees}}};"))
}
pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use {
let visibility = match visibility {
None => String::new(),
- Some(it) => format!("{} ", it),
+ Some(it) => format!("{it} "),
};
- ast_from_text(&format!("{}use {};", visibility, use_tree))
+ ast_from_text(&format!("{visibility}use {use_tree};"))
}
pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr {
- ast_from_text(&format!("fn f() {{ {} {} }}", path, fields))
+ ast_from_text(&format!("fn f() {{ {path} {fields} }}"))
}
pub fn record_expr_field_list(
fields: impl IntoIterator<Item = ast::RecordExprField>,
) -> ast::RecordExprFieldList {
let fields = fields.into_iter().join(", ");
- ast_from_text(&format!("fn f() {{ S {{ {} }} }}", fields))
+ ast_from_text(&format!("fn f() {{ S {{ {fields} }} }}"))
}
pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField {
return match expr {
- Some(expr) => from_text(&format!("{}: {}", name, expr)),
+ Some(expr) => from_text(&format!("{name}: {expr}")),
None => from_text(&name.to_string()),
};
fn from_text(text: &str) -> ast::RecordExprField {
- ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text))
+ ast_from_text(&format!("fn f() {{ S {{ {text}, }} }}"))
}
}
) -> ast::RecordField {
let visibility = match visibility {
None => String::new(),
- Some(it) => format!("{} ", it),
+ Some(it) => format!("{it} "),
};
- ast_from_text(&format!("struct S {{ {}{}: {}, }}", visibility, name, ty))
+ ast_from_text(&format!("struct S {{ {visibility}{name}: {ty}, }}"))
}
// TODO
) -> ast::BlockExpr {
let mut buf = "{\n".to_string();
for stmt in stmts.into_iter() {
- format_to!(buf, " {}\n", stmt);
+ format_to!(buf, " {stmt}\n");
}
if let Some(tail_expr) = tail_expr {
- format_to!(buf, " {}\n", tail_expr);
+ format_to!(buf, " {tail_expr}\n");
}
buf += "}";
- ast_from_text(&format!("fn f() {}", buf))
+ ast_from_text(&format!("fn f() {buf}"))
}
/// Ideally this function wouldn't exist since it involves manual indenting.
let mut buf = "{\n".to_string();
for node_or_token in elements.into_iter() {
match node_or_token {
- rowan::NodeOrToken::Node(n) => format_to!(buf, " {}\n", n),
+ rowan::NodeOrToken::Node(n) => format_to!(buf, " {n}\n"),
rowan::NodeOrToken::Token(t) if t.kind() == SyntaxKind::COMMENT => {
- format_to!(buf, " {}\n", t)
+ format_to!(buf, " {t}\n")
}
_ => (),
}
}
if let Some(tail_expr) = tail_expr {
- format_to!(buf, " {}\n", tail_expr);
+ format_to!(buf, " {tail_expr}\n");
}
buf += "}";
- ast_from_text(&format!("fn f() {}", buf))
+ ast_from_text(&format!("fn f() {buf}"))
}
pub fn expr_unit() -> ast::Expr {
}
pub fn expr_literal(text: &str) -> ast::Literal {
assert_eq!(text.trim(), text);
- ast_from_text(&format!("fn f() {{ let _ = {}; }}", text))
+ ast_from_text(&format!("fn f() {{ let _ = {text}; }}"))
}
pub fn expr_empty_block() -> ast::Expr {
}
pub fn expr_continue(label: Option<ast::Lifetime>) -> ast::Expr {
match label {
- Some(label) => expr_from_text(&format!("continue {}", label)),
+ Some(label) => expr_from_text(&format!("continue {label}")),
None => expr_from_text("continue"),
}
}
// Consider `op: SyntaxKind` instead for nicer syntax at the call-site?
pub fn expr_bin_op(lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr {
- expr_from_text(&format!("{} {} {}", lhs, op, rhs))
+ expr_from_text(&format!("{lhs} {op} {rhs}"))
}
pub fn expr_break(label: Option<ast::Lifetime>, expr: Option<ast::Expr>) -> ast::Expr {
let mut s = String::from("break");
if let Some(label) = label {
- format_to!(s, " {}", label);
+ format_to!(s, " {label}");
}
if let Some(expr) = expr {
- format_to!(s, " {}", expr);
+ format_to!(s, " {expr}");
}
expr_from_text(&s)
}
pub fn expr_return(expr: Option<ast::Expr>) -> ast::Expr {
match expr {
- Some(expr) => expr_from_text(&format!("return {}", expr)),
+ Some(expr) => expr_from_text(&format!("return {expr}")),
None => expr_from_text("return"),
}
}
pub fn expr_try(expr: ast::Expr) -> ast::Expr {
- expr_from_text(&format!("{}?", expr))
+ expr_from_text(&format!("{expr}?"))
}
pub fn expr_await(expr: ast::Expr) -> ast::Expr {
- expr_from_text(&format!("{}.await", expr))
+ expr_from_text(&format!("{expr}.await"))
}
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
- expr_from_text(&format!("match {} {}", expr, match_arm_list))
+ expr_from_text(&format!("match {expr} {match_arm_list}"))
}
pub fn expr_if(
condition: ast::Expr,
else_branch: Option<ast::ElseBranch>,
) -> ast::Expr {
let else_branch = match else_branch {
- Some(ast::ElseBranch::Block(block)) => format!("else {}", block),
- Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {}", if_expr),
+ Some(ast::ElseBranch::Block(block)) => format!("else {block}"),
+ Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"),
None => String::new(),
};
- expr_from_text(&format!("if {} {} {}", condition, then_branch, else_branch))
+ expr_from_text(&format!("if {condition} {then_branch} {else_branch}"))
}
pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr {
- expr_from_text(&format!("for {} in {} {}", pat, expr, block))
+ expr_from_text(&format!("for {pat} in {expr} {block}"))
}
pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr {
- expr_from_text(&format!("loop {}", block))
+ expr_from_text(&format!("loop {block}"))
}
pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
let token = token(op);
- expr_from_text(&format!("{}{}", token, expr))
+ expr_from_text(&format!("{token}{expr}"))
}
pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
- expr_from_text(&format!("{}{}", f, arg_list))
+ expr_from_text(&format!("{f}{arg_list}"))
}
pub fn expr_method_call(
receiver: ast::Expr,
method: ast::NameRef,
arg_list: ast::ArgList,
) -> ast::Expr {
- expr_from_text(&format!("{}.{}{}", receiver, method, arg_list))
+ expr_from_text(&format!("{receiver}.{method}{arg_list}"))
}
pub fn expr_macro_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
- expr_from_text(&format!("{}!{}", f, arg_list))
+ expr_from_text(&format!("{f}!{arg_list}"))
}
pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr {
- expr_from_text(&if exclusive { format!("&mut {}", expr) } else { format!("&{}", expr) })
+ expr_from_text(&if exclusive { format!("&mut {expr}") } else { format!("&{expr}") })
}
pub fn expr_closure(pats: impl IntoIterator<Item = ast::Param>, expr: ast::Expr) -> ast::Expr {
let params = pats.into_iter().join(", ");
- expr_from_text(&format!("|{}| {}", params, expr))
+ expr_from_text(&format!("|{params}| {expr}"))
}
pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr {
- expr_from_text(&format!("{}.{}", receiver, field))
+ expr_from_text(&format!("{receiver}.{field}"))
}
pub fn expr_paren(expr: ast::Expr) -> ast::Expr {
- expr_from_text(&format!("({})", expr))
+ expr_from_text(&format!("({expr})"))
}
pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::Expr {
let expr = elements.into_iter().format(", ");
- expr_from_text(&format!("({})", expr))
+ expr_from_text(&format!("({expr})"))
}
pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
- expr_from_text(&format!("{} = {}", lhs, rhs))
+ expr_from_text(&format!("{lhs} = {rhs}"))
}
fn expr_from_text(text: &str) -> ast::Expr {
- ast_from_text(&format!("const C: () = {};", text))
+ ast_from_text(&format!("const C: () = {text};"))
}
pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
- ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
+ ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};"))
}
pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
- ast_from_text(&format!("fn main() {{ ()({}) }}", args.into_iter().format(", ")))
+ let args = args.into_iter().format(", ");
+ ast_from_text(&format!("fn main() {{ ()({args}) }}"))
}
pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
if mut_ {
s.push_str("mut ");
}
- format_to!(s, "{}", name);
+ format_to!(s, "{name}");
s.push_str(": ())");
ast_from_text(&s)
}
return from_text("_");
fn from_text(text: &str) -> ast::WildcardPat {
- ast_from_text(&format!("fn f({}: ())", text))
+ ast_from_text(&format!("fn f({text}: ())"))
}
}
return from_text(lit);
fn from_text(text: &str) -> ast::LiteralPat {
- ast_from_text(&format!("fn f() {{ match x {{ {} => {{}} }} }}", text))
+ ast_from_text(&format!("fn f() {{ match x {{ {text} => {{}} }} }}"))
}
}
if count == 1 {
pats_str.push(',');
}
- return from_text(&format!("({})", pats_str));
+ return from_text(&format!("({pats_str})"));
fn from_text(text: &str) -> ast::TuplePat {
- ast_from_text(&format!("fn f({}: ())", text))
+ ast_from_text(&format!("fn f({text}: ())"))
}
}
pats: impl IntoIterator<Item = ast::Pat>,
) -> ast::TupleStructPat {
let pats_str = pats.into_iter().join(", ");
- return from_text(&format!("{}({})", path, pats_str));
+ return from_text(&format!("{path}({pats_str})"));
fn from_text(text: &str) -> ast::TupleStructPat {
- ast_from_text(&format!("fn f({}: ())", text))
+ ast_from_text(&format!("fn f({text}: ())"))
}
}
pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> ast::RecordPat {
let pats_str = pats.into_iter().join(", ");
- return from_text(&format!("{} {{ {} }}", path, pats_str));
+ return from_text(&format!("{path} {{ {pats_str} }}"));
fn from_text(text: &str) -> ast::RecordPat {
- ast_from_text(&format!("fn f({}: ())", text))
+ ast_from_text(&format!("fn f({text}: ())"))
}
}
pub fn record_pat_with_fields(path: ast::Path, fields: ast::RecordPatFieldList) -> ast::RecordPat {
- ast_from_text(&format!("fn f({} {}: ()))", path, fields))
+ ast_from_text(&format!("fn f({path} {fields}: ()))"))
}
pub fn record_pat_field_list(
fields: impl IntoIterator<Item = ast::RecordPatField>,
) -> ast::RecordPatFieldList {
let fields = fields.into_iter().join(", ");
- ast_from_text(&format!("fn f(S {{ {} }}: ()))", fields))
+ ast_from_text(&format!("fn f(S {{ {fields} }}: ()))"))
}
pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField {
- ast_from_text(&format!("fn f(S {{ {}: {} }}: ()))", name_ref, pat))
+ ast_from_text(&format!("fn f(S {{ {name_ref}: {pat} }}: ()))"))
}
pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField {
- ast_from_text(&format!("fn f(S {{ {} }}: ()))", name_ref))
+ ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))"))
}
/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
pub fn path_pat(path: ast::Path) -> ast::Pat {
return from_text(&path.to_string());
fn from_text(text: &str) -> ast::Pat {
- ast_from_text(&format!("fn f({}: ())", text))
+ ast_from_text(&format!("fn f({text}: ())"))
}
}
) -> ast::MatchArm {
let pats_str = pats.into_iter().join(" | ");
return match guard {
- Some(guard) => from_text(&format!("{} if {} => {}", pats_str, guard, expr)),
- None => from_text(&format!("{} => {}", pats_str, expr)),
+ Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")),
+ None => from_text(&format!("{pats_str} => {expr}")),
};
fn from_text(text: &str) -> ast::MatchArm {
- ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
+ ast_from_text(&format!("fn f() {{ match () {{{text}}} }}"))
}
}
expr: ast::Expr,
) -> ast::MatchArm {
let pats_str = pats.into_iter().join(" | ");
- return from_text(&format!("{} if {} => {}", pats_str, guard, expr));
+ return from_text(&format!("{pats_str} if {guard} => {expr}"));
fn from_text(text: &str) -> ast::MatchArm {
- ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
+ ast_from_text(&format!("fn f() {{ match () {{{text}}} }}"))
}
}
.map(|arm| {
let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like());
let comma = if needs_comma { "," } else { "" };
- format!(" {}{}\n", arm.syntax(), comma)
+ let arm = arm.syntax();
+ format!(" {arm}{comma}\n")
})
.collect::<String>();
return from_text(&arms_str);
fn from_text(text: &str) -> ast::MatchArmList {
- ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text))
+ ast_from_text(&format!("fn f() {{ match () {{\n{text}}} }}"))
}
}
bounds: impl IntoIterator<Item = ast::TypeBound>,
) -> ast::WherePred {
let bounds = bounds.into_iter().join(" + ");
- return from_text(&format!("{}: {}", path, bounds));
+ return from_text(&format!("{path}: {bounds}"));
fn from_text(text: &str) -> ast::WherePred {
- ast_from_text(&format!("fn f() where {} {{ }}", text))
+ ast_from_text(&format!("fn f() where {text} {{ }}"))
}
}
return from_text(preds.as_str());
fn from_text(text: &str) -> ast::WhereClause {
- ast_from_text(&format!("fn f() where {} {{ }}", text))
+ ast_from_text(&format!("fn f() where {text} {{ }}"))
}
}
initializer: Option<ast::Expr>,
) -> ast::LetStmt {
let mut text = String::new();
- format_to!(text, "let {}", pattern);
+ format_to!(text, "let {pattern}");
if let Some(ty) = ty {
- format_to!(text, ": {}", ty);
+ format_to!(text, ": {ty}");
}
match initializer {
- Some(it) => format_to!(text, " = {};", it),
+ Some(it) => format_to!(text, " = {it};"),
None => format_to!(text, ";"),
};
- ast_from_text(&format!("fn f() {{ {} }}", text))
+ ast_from_text(&format!("fn f() {{ {text} }}"))
}
pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
let semi = if expr.is_block_like() { "" } else { ";" };
- ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi))
+ ast_from_text(&format!("fn f() {{ {expr}{semi} (); }}"))
}
pub fn item_const(
) -> ast::Const {
let visibility = match visibility {
None => String::new(),
- Some(it) => format!("{} ", it),
+ Some(it) => format!("{it} "),
};
- ast_from_text(&format!("{} const {}: {} = {};", visibility, name, ty, expr))
+ ast_from_text(&format!("{visibility} const {name}: {ty} = {expr};"))
}
pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param {
- ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty))
+ ast_from_text(&format!("fn f({pat}: {ty}) {{ }}"))
}
pub fn self_param() -> ast::SelfParam {
}
pub fn ret_type(ty: ast::Type) -> ast::RetType {
- ast_from_text(&format!("fn f() -> {} {{ }}", ty))
+ ast_from_text(&format!("fn f() -> {ty} {{ }}"))
}
pub fn param_list(
) -> ast::ParamList {
let args = pats.into_iter().join(", ");
let list = match self_param {
- Some(self_param) if args.is_empty() => format!("fn f({}) {{ }}", self_param),
- Some(self_param) => format!("fn f({}, {}) {{ }}", self_param, args),
- None => format!("fn f({}) {{ }}", args),
+ Some(self_param) if args.is_empty() => format!("fn f({self_param}) {{ }}"),
+ Some(self_param) => format!("fn f({self_param}, {args}) {{ }}"),
+ None => format!("fn f({args}) {{ }}"),
};
ast_from_text(&list)
}
pub fn type_param(name: ast::Name, ty: Option<ast::TypeBoundList>) -> ast::TypeParam {
let bound = match ty {
- Some(it) => format!(": {}", it),
+ Some(it) => format!(": {it}"),
None => String::new(),
};
- ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound))
+ ast_from_text(&format!("fn f<{name}{bound}>() {{ }}"))
}
pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {
- ast_from_text(&format!("fn f<{}>() {{ }}", lifetime))
+ ast_from_text(&format!("fn f<{lifetime}>() {{ }}"))
}
pub fn generic_param_list(
pats: impl IntoIterator<Item = ast::GenericParam>,
) -> ast::GenericParamList {
let args = pats.into_iter().join(", ");
- ast_from_text(&format!("fn f<{}>() {{ }}", args))
+ ast_from_text(&format!("fn f<{args}>() {{ }}"))
}
pub fn visibility_pub_crate() -> ast::Visibility {
pub fn tuple_field_list(fields: impl IntoIterator<Item = ast::TupleField>) -> ast::TupleFieldList {
let fields = fields.into_iter().join(", ");
- ast_from_text(&format!("struct f({});", fields))
+ ast_from_text(&format!("struct f({fields});"))
}
pub fn record_field_list(
fields: impl IntoIterator<Item = ast::RecordField>,
) -> ast::RecordFieldList {
let fields = fields.into_iter().join(", ");
- ast_from_text(&format!("struct f {{ {} }}", fields))
+ ast_from_text(&format!("struct f {{ {fields} }}"))
}
pub fn tuple_field(visibility: Option<ast::Visibility>, ty: ast::Type) -> ast::TupleField {
let visibility = match visibility {
None => String::new(),
- Some(it) => format!("{} ", it),
+ Some(it) => format!("{it} "),
};
- ast_from_text(&format!("struct f({}{});", visibility, ty))
+ ast_from_text(&format!("struct f({visibility}{ty});"))
}
pub fn variant(name: ast::Name, field_list: Option<ast::FieldList>) -> ast::Variant {
let field_list = match field_list {
None => String::new(),
Some(it) => match it {
- ast::FieldList::RecordFieldList(record) => format!(" {}", record),
- ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple),
+ ast::FieldList::RecordFieldList(record) => format!(" {record}"),
+ ast::FieldList::TupleFieldList(tuple) => format!("{tuple}"),
},
};
- ast_from_text(&format!("enum f {{ {}{} }}", name, field_list))
+ ast_from_text(&format!("enum f {{ {name}{field_list} }}"))
}
pub fn fn_(
is_async: bool,
) -> ast::Fn {
let type_params = match type_params {
- Some(type_params) => format!("{}", type_params),
+ Some(type_params) => format!("{type_params}"),
None => "".into(),
};
let ret_type = match ret_type {
- Some(ret_type) => format!("{} ", ret_type),
+ Some(ret_type) => format!("{ret_type} "),
None => "".into(),
};
let visibility = match visibility {
None => String::new(),
- Some(it) => format!("{} ", it),
+ Some(it) => format!("{it} "),
};
let async_literal = if is_async { "async " } else { "" };
ast_from_text(&format!(
- "{}{}fn {}{}{} {}{}",
- visibility, async_literal, fn_name, type_params, params, ret_type, body
+ "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{body}",
))
}
let type_params = generic_param_list.map_or_else(String::new, |it| it.to_string());
let visibility = match visibility {
None => String::new(),
- Some(it) => format!("{} ", it),
+ Some(it) => format!("{it} "),
};
- ast_from_text(&format!(
- "{}struct {}{}{}{}",
- visibility, strukt_name, type_params, field_list, semicolon
- ))
+ ast_from_text(&format!("{visibility}struct {strukt_name}{type_params}{field_list}{semicolon}",))
}
#[track_caller]
let node = match parse.tree().syntax().descendants().find_map(N::cast) {
Some(it) => it,
None => {
- panic!("Failed to make ast node `{}` from text {}", std::any::type_name::<N>(), text)
+ let node = std::any::type_name::<N>();
+ panic!("Failed to make ast node `{node}` from text {text}")
}
};
let node = node.clone_subtree();
.descendants_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == kind)
- .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
+ .unwrap_or_else(|| panic!("unhandled token: {kind:?}"))
}
pub mod tokens {
pub fn literal(text: &str) -> SyntaxToken {
assert_eq!(text.trim(), text);
- let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text));
+ let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {text}; }}"));
lit.syntax().first_child_or_token().unwrap().into_token().unwrap()
}
pub fn float_value(&self) -> Option<f64> {
let (_, text, _) = self.split_into_parts();
- text.parse::<f64>().ok()
+ text.replace('_', "").parse::<f64>().ok()
}
}
pub fn value(&self) -> Option<f64> {
let (text, _) = self.split_into_parts();
- text.parse::<f64>().ok()
+ text.replace('_', "").parse::<f64>().ok()
}
}
assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into());
}
+ fn check_float_value(lit: &str, expected: impl Into<Option<f64>> + Copy) {
+ assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
+ assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into());
+ }
+
+ fn check_int_value(lit: &str, expected: impl Into<Option<u128>>) {
+ assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
+ }
+
#[test]
fn test_float_number_suffix() {
check_float_suffix("123.0", None);
check_string_value(r"\nfoobar", "\nfoobar");
check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
}
+
+ #[test]
+ fn test_value_underscores() {
+ check_float_value("3.141592653589793_f64", 3.141592653589793_f64);
+ check_float_value("1__0.__0__f32", 10.0);
+ check_int_value("0b__1_0_", 2);
+ check_int_value("1_1_1_1_1_1", 111111);
+ }
}
impl ast::Char {
quote! {
impl AstNode for #name {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- #(#kinds)|* => true,
- _ => false,
- }
+ matches!(kind, #(#kinds)|*)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
}
impl AstNode for #name {
fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- #(#kinds)|* => true,
- _ => false,
- }
+ matches!(kind, #(#kinds)|*)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
Self::can_cast(syntax.kind()).then(|| #name { syntax })
impl SyntaxKind {
pub fn is_keyword(self) -> bool {
- match self {
- #(#all_keywords)|* => true,
- _ => false,
- }
+ matches!(self, #(#all_keywords)|*)
}
pub fn is_punct(self) -> bool {
- match self {
- #(#punctuation)|* => true,
- _ => false,
- }
+
+ matches!(self, #(#punctuation)|*)
+
}
pub fn is_literal(self) -> bool {
- match self {
- #(#literals)|* => true,
- _ => false,
- }
+ matches!(self, #(#literals)|*)
}
pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
.map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value))
}
+ /// Returns an iterator over the arena’s values.
+ ///
+ /// ```
+ /// let mut arena = la_arena::Arena::new();
+ /// let idx1 = arena.alloc(20);
+ /// let idx2 = arena.alloc(40);
+ /// let idx3 = arena.alloc(60);
+ ///
+ /// let mut iterator = arena.values();
+ /// assert_eq!(iterator.next(), Some(&20));
+ /// assert_eq!(iterator.next(), Some(&40));
+ /// assert_eq!(iterator.next(), Some(&60));
+ /// ```
+ pub fn values(&mut self) -> impl Iterator<Item = &T> + ExactSizeIterator + DoubleEndedIterator {
+ self.data.iter()
+ }
+
+ /// Returns an iterator over the arena’s mutable values.
+ ///
+ /// ```
+ /// let mut arena = la_arena::Arena::new();
+ /// let idx1 = arena.alloc(20);
+ ///
+ /// assert_eq!(arena[idx1], 20);
+ ///
+ /// let mut iterator = arena.values_mut();
+ /// *iterator.next().unwrap() = 10;
+ /// drop(iterator);
+ ///
+ /// assert_eq!(arena[idx1], 10);
+ /// ```
+ pub fn values_mut(
+ &mut self,
+ ) -> impl Iterator<Item = &mut T> + ExactSizeIterator + DoubleEndedIterator {
+ self.data.iter_mut()
+ }
+
/// Reallocates the arena to make it take up as little space as possible.
pub fn shrink_to_fit(&mut self) {
self.data.shrink_to_fit();