Auto merge of #122822 - matthiaskrgr:rollup-rjgmnbe, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #122222 (deref patterns: bare-bones feature gate and typechecking) - #122358 (Don't ICE when encountering bound regions in generator interior type) - #122696 (Add bare metal riscv32 target.) - #122773 (make "expected paren or brace" error translatable) - #122795 (Inherit `RUSTC_BOOTSTRAP` when testing wasm) - #122799 (Replace closures with `_` when suggesting fully qualified path for method call) - #122801 (Fix misc printing issues in emit=stable_mir) - #122806 (Make `type_ascribe!` not a built-in) Failed merges: - #122771 (add some comments to hir::ModuleItems) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
2627e9f301
60 changed files with 752 additions and 720 deletions
|
@ -413,7 +413,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
}
|
||||
PatKind::Box(..) => {
|
||||
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
|
||||
if !self.features.deref_patterns {
|
||||
// Allow box patterns under `deref_patterns`.
|
||||
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
|
||||
}
|
||||
}
|
||||
PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
|
||||
gate!(
|
||||
|
@ -607,13 +610,16 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
};
|
||||
}
|
||||
|
||||
if !visitor.features.deref_patterns {
|
||||
// Allow box patterns under `deref_patterns`.
|
||||
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
|
||||
}
|
||||
gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
|
||||
// Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
|
||||
// used to be gated under associated_type_bounds, which are right above, so RTN needs to
|
||||
// be too.
|
||||
gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
|
||||
gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
|
||||
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
|
||||
gate_all_legacy_dont_use!(
|
||||
exclusive_range_pattern,
|
||||
"exclusive range pattern syntax is experimental"
|
||||
|
|
|
@ -49,7 +49,6 @@ mod log_syntax;
|
|||
mod source_util;
|
||||
mod test;
|
||||
mod trace_macros;
|
||||
mod type_ascribe;
|
||||
mod util;
|
||||
|
||||
pub mod asm;
|
||||
|
@ -99,7 +98,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
|||
std_panic: edition_panic::expand_panic,
|
||||
stringify: source_util::expand_stringify,
|
||||
trace_macros: trace_macros::expand_trace_macros,
|
||||
type_ascribe: type_ascribe::expand_type_ascribe,
|
||||
unreachable: edition_panic::expand_unreachable,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{token, Expr, ExprKind, Ty};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub fn expand_type_ascribe(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
tts: TokenStream,
|
||||
) -> MacroExpanderResult<'static> {
|
||||
let (expr, ty) = match parse_ascribe(cx, tts) {
|
||||
Ok(parsed) => parsed,
|
||||
Err(err) => {
|
||||
let guar = err.emit();
|
||||
return ExpandResult::Ready(DummyResult::any(span, guar));
|
||||
}
|
||||
};
|
||||
|
||||
let asc_expr = cx.expr(span, ExprKind::Type(expr, ty));
|
||||
|
||||
ExpandResult::Ready(MacEager::expr(asc_expr))
|
||||
}
|
||||
|
||||
fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Expr>, P<Ty>)> {
|
||||
let mut parser = cx.new_parser_from_tts(stream);
|
||||
|
||||
let expr = parser.parse_expr()?;
|
||||
parser.expect(&token::Comma)?;
|
||||
|
||||
let ty = parser.parse_ty()?;
|
||||
|
||||
Ok((expr, ty))
|
||||
}
|
|
@ -33,6 +33,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding
|
|||
expand_expected_comma_in_list =
|
||||
expected token: `,`
|
||||
|
||||
expand_expected_paren_or_brace =
|
||||
expected `(` or `{"{"}`, found `{$token}`
|
||||
|
||||
expand_explain_doc_comment_inner =
|
||||
inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
|
||||
|
||||
|
|
|
@ -448,3 +448,11 @@ pub struct InvalidFragmentSpecifier {
|
|||
pub fragment: Ident,
|
||||
pub help: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(expand_expected_paren_or_brace)]
|
||||
pub struct ExpectedParenOrBrace<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub token: Cow<'a, str>,
|
||||
}
|
||||
|
|
|
@ -194,9 +194,11 @@ fn parse_tree<'a>(
|
|||
}
|
||||
Delimiter::Parenthesis => {}
|
||||
_ => {
|
||||
let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
|
||||
let msg = format!("expected `(` or `{{`, found `{tok}`");
|
||||
sess.dcx().span_err(delim_span.entire(), msg);
|
||||
let token = pprust::token_kind_to_string(&token::OpenDelim(delim));
|
||||
sess.dcx().emit_err(errors::ExpectedParenOrBrace {
|
||||
span: delim_span.entire(),
|
||||
token,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -436,6 +436,8 @@ declare_features! (
|
|||
(unstable, deprecated_safe, "1.61.0", Some(94978)),
|
||||
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
||||
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
|
||||
/// Allows deref patterns.
|
||||
(incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121)),
|
||||
/// Controls errors in trait implementations.
|
||||
(unstable, do_not_recommend, "1.67.0", Some(51992)),
|
||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
||||
|
|
|
@ -565,7 +565,7 @@ fn check_assoc_const_binding_type<'tcx>(
|
|||
let mut guar = ty.visit_with(&mut collector).break_value();
|
||||
|
||||
let ty_note = ty
|
||||
.make_suggestable(tcx, false)
|
||||
.make_suggestable(tcx, false, None)
|
||||
.map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty });
|
||||
|
||||
let enclosing_item_owner_id = tcx
|
||||
|
|
|
@ -1371,7 +1371,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
|||
// recursive function definition to leak out into the fn sig.
|
||||
let mut should_recover = false;
|
||||
|
||||
if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false) {
|
||||
if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
|
||||
diag.span_suggestion(
|
||||
ty.span,
|
||||
"replace with the correct return type",
|
||||
|
@ -1449,7 +1449,7 @@ fn suggest_impl_trait<'tcx>(
|
|||
let ty::Tuple(types) = *args_tuple.kind() else {
|
||||
return None;
|
||||
};
|
||||
let types = types.make_suggestable(tcx, false)?;
|
||||
let types = types.make_suggestable(tcx, false, None)?;
|
||||
let maybe_ret =
|
||||
if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
|
||||
Some(format!(
|
||||
|
@ -1507,7 +1507,7 @@ fn suggest_impl_trait<'tcx>(
|
|||
// FIXME(compiler-errors): We may benefit from resolving regions here.
|
||||
if ocx.select_where_possible().is_empty()
|
||||
&& let item_ty = infcx.resolve_vars_if_possible(item_ty)
|
||||
&& let Some(item_ty) = item_ty.make_suggestable(tcx, false)
|
||||
&& let Some(item_ty) = item_ty.make_suggestable(tcx, false, None)
|
||||
&& let Some(sugg) = formatter(
|
||||
tcx,
|
||||
infcx.resolve_vars_if_possible(args),
|
||||
|
|
|
@ -47,7 +47,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
let ty = tcx.fold_regions(ty, |r, _| {
|
||||
if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r }
|
||||
});
|
||||
let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false) {
|
||||
let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false, None) {
|
||||
(ty, Some((span, Applicability::MachineApplicable)))
|
||||
} else {
|
||||
(ty, None)
|
||||
|
@ -587,7 +587,7 @@ fn infer_placeholder_type<'a>(
|
|||
suggestions.clear();
|
||||
}
|
||||
|
||||
if let Some(ty) = ty.make_suggestable(tcx, false) {
|
||||
if let Some(ty) = ty.make_suggestable(tcx, false, None) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
format!("provide a type for the {kind}"),
|
||||
|
@ -606,7 +606,7 @@ fn infer_placeholder_type<'a>(
|
|||
let mut diag = bad_placeholder(tcx, vec![span], kind);
|
||||
|
||||
if !ty.references_error() {
|
||||
if let Some(ty) = ty.make_suggestable(tcx, false) {
|
||||
if let Some(ty) = ty.make_suggestable(tcx, false, None) {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"replace with the correct type",
|
||||
|
|
|
@ -809,7 +809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return true;
|
||||
}
|
||||
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
|
||||
if let Some(found) = found.make_suggestable(self.tcx, false) {
|
||||
if let Some(found) = found.make_suggestable(self.tcx, false, None) {
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() },
|
||||
|
|
|
@ -601,8 +601,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if let Some(output_def_id) = output_def_id
|
||||
&& let Some(trait_def_id) = trait_def_id
|
||||
&& self.tcx.parent(output_def_id) == trait_def_id
|
||||
&& let Some(output_ty) =
|
||||
output_ty.make_suggestable(self.tcx, false)
|
||||
&& let Some(output_ty) = output_ty
|
||||
.make_suggestable(self.tcx, false, None)
|
||||
{
|
||||
Some(("Output", output_ty))
|
||||
} else {
|
||||
|
|
|
@ -18,8 +18,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
|
|||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{BytePos, DUMMY_SP};
|
||||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
use rustc_target::abi::FieldIdx;
|
||||
use rustc_trait_selection::traits::{ObligationCause, Pattern};
|
||||
use ty::VariantDef;
|
||||
|
@ -211,6 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
PatKind::Tuple(elements, ddpos) => {
|
||||
self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
|
||||
}
|
||||
PatKind::Box(inner) if self.tcx.features().deref_patterns => {
|
||||
self.check_pat_deref(pat.span, inner, expected, pat_info)
|
||||
}
|
||||
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
|
||||
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
|
||||
PatKind::Slice(before, slice, after) => {
|
||||
|
@ -1975,6 +1977,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
box_ty
|
||||
}
|
||||
|
||||
fn check_pat_deref(
|
||||
&self,
|
||||
span: Span,
|
||||
inner: &'tcx Pat<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
pat_info: PatInfo<'tcx, '_>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
// FIXME(deref_patterns): use `DerefPure` for soundness
|
||||
// FIXME(deref_patterns): use `DerefMut` when required
|
||||
// <expected as Deref>::Target
|
||||
let ty = Ty::new_projection(
|
||||
tcx,
|
||||
tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
|
||||
[expected],
|
||||
);
|
||||
let ty = self.normalize(span, ty);
|
||||
let ty = self.try_structurally_resolve_type(span, ty);
|
||||
self.check_pat(inner, ty, pat_info);
|
||||
expected
|
||||
}
|
||||
|
||||
// Precondition: Pat is Ref(inner)
|
||||
fn check_pat_ref(
|
||||
&self,
|
||||
|
|
|
@ -546,40 +546,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => {
|
||||
let mut printer = fmt_printer(self, Namespace::ValueNS);
|
||||
printer.print_def_path(def_id, args).unwrap();
|
||||
let def_path = printer.into_buffer();
|
||||
let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
|
||||
span: rustc_span::DUMMY_SP,
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
}));
|
||||
if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) {
|
||||
let mut printer = fmt_printer(self, Namespace::ValueNS);
|
||||
printer.print_def_path(def_id, args).unwrap();
|
||||
let def_path = printer.into_buffer();
|
||||
|
||||
// We only care about whether we have to add `&` or `&mut ` for now.
|
||||
// This is the case if the last adjustment is a borrow and the
|
||||
// first adjustment was not a builtin deref.
|
||||
let adjustment = match typeck_results.expr_adjustments(receiver) {
|
||||
[
|
||||
Adjustment { kind: Adjust::Deref(None), target: _ },
|
||||
..,
|
||||
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
|
||||
] => "",
|
||||
[
|
||||
..,
|
||||
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
|
||||
] => hir::Mutability::from(*mut_).ref_prefix_str(),
|
||||
_ => "",
|
||||
};
|
||||
// We only care about whether we have to add `&` or `&mut ` for now.
|
||||
// This is the case if the last adjustment is a borrow and the
|
||||
// first adjustment was not a builtin deref.
|
||||
let adjustment = match typeck_results.expr_adjustments(receiver) {
|
||||
[
|
||||
Adjustment { kind: Adjust::Deref(None), target: _ },
|
||||
..,
|
||||
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
|
||||
] => "",
|
||||
[
|
||||
..,
|
||||
Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)),
|
||||
target: _,
|
||||
},
|
||||
] => hir::Mutability::from(*mut_).ref_prefix_str(),
|
||||
_ => "",
|
||||
};
|
||||
|
||||
multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
|
||||
receiver.span,
|
||||
def_path,
|
||||
adjustment,
|
||||
successor,
|
||||
));
|
||||
multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
|
||||
receiver.span,
|
||||
def_path,
|
||||
adjustment,
|
||||
successor,
|
||||
));
|
||||
}
|
||||
}
|
||||
InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
|
||||
let ty_info = ty_to_string(self, ty, None);
|
||||
multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
|
||||
ty_info,
|
||||
data,
|
||||
should_wrap_expr,
|
||||
));
|
||||
let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
|
||||
span: rustc_span::DUMMY_SP,
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
}));
|
||||
if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) {
|
||||
let ty_info = ty_to_string(self, ty, None);
|
||||
multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
|
||||
ty_info,
|
||||
data,
|
||||
should_wrap_expr,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
match error_code {
|
||||
|
|
|
@ -647,6 +647,7 @@ impl<'tcx> Pat<'tcx> {
|
|||
AscribeUserType { subpattern, .. }
|
||||
| Binding { subpattern: Some(subpattern), .. }
|
||||
| Deref { subpattern }
|
||||
| DerefPattern { subpattern }
|
||||
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
|
||||
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
||||
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
||||
|
@ -762,6 +763,11 @@ pub enum PatKind<'tcx> {
|
|||
subpattern: Box<Pat<'tcx>>,
|
||||
},
|
||||
|
||||
/// Deref pattern, written `box P` for now.
|
||||
DerefPattern {
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
},
|
||||
|
||||
/// One of the following:
|
||||
/// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
|
||||
/// exhaustiveness checking will detect if you use the same string twice in different
|
||||
|
@ -1172,6 +1178,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
|||
}
|
||||
write!(f, "{subpattern}")
|
||||
}
|
||||
PatKind::DerefPattern { ref subpattern } => {
|
||||
write!(f, "k#deref {subpattern}")
|
||||
}
|
||||
PatKind::Constant { value } => write!(f, "{value}"),
|
||||
PatKind::InlineConstant { def: _, ref subpattern } => {
|
||||
write!(f, "{} (from inline const)", subpattern)
|
||||
|
|
|
@ -229,6 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||
match &pat.kind {
|
||||
AscribeUserType { subpattern, ascription: _ }
|
||||
| Deref { subpattern }
|
||||
| DerefPattern { subpattern }
|
||||
| Binding {
|
||||
subpattern: Some(subpattern),
|
||||
mutability: _,
|
||||
|
|
|
@ -91,7 +91,12 @@ pub trait IsSuggestable<'tcx>: Sized {
|
|||
/// inference variables to be suggestable.
|
||||
fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
|
||||
|
||||
fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<Self>;
|
||||
fn make_suggestable(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
infer_suggestable: bool,
|
||||
placeholder: Option<Ty<'tcx>>,
|
||||
) -> Option<Self>;
|
||||
}
|
||||
|
||||
impl<'tcx, T> IsSuggestable<'tcx> for T
|
||||
|
@ -103,8 +108,13 @@ where
|
|||
self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
|
||||
}
|
||||
|
||||
fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<T> {
|
||||
self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable }).ok()
|
||||
fn make_suggestable(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
infer_suggestable: bool,
|
||||
placeholder: Option<Ty<'tcx>>,
|
||||
) -> Option<T> {
|
||||
self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable, placeholder }).ok()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -559,6 +569,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
|
|||
pub struct MakeSuggestableFolder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
infer_suggestable: bool,
|
||||
placeholder: Option<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
|
||||
|
@ -572,19 +583,24 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
|
|||
let t = match *t.kind() {
|
||||
Infer(InferTy::TyVar(_)) if self.infer_suggestable => t,
|
||||
|
||||
FnDef(def_id, args) => {
|
||||
FnDef(def_id, args) if self.placeholder.is_none() => {
|
||||
Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).instantiate(self.tcx, args))
|
||||
}
|
||||
|
||||
// FIXME(compiler-errors): We could replace these with infer, I guess.
|
||||
Closure(..)
|
||||
| FnDef(..)
|
||||
| Infer(..)
|
||||
| Coroutine(..)
|
||||
| CoroutineWitness(..)
|
||||
| Bound(_, _)
|
||||
| Placeholder(_)
|
||||
| Error(_) => {
|
||||
return Err(());
|
||||
if let Some(placeholder) = self.placeholder {
|
||||
// We replace these with infer (which is passed in from an infcx).
|
||||
placeholder
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
Alias(Opaque, AliasTy { def_id, .. }) => {
|
||||
|
|
|
@ -682,6 +682,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
/// Return the set of types that should be taken into account when checking
|
||||
/// trait bounds on a coroutine's internal state.
|
||||
// FIXME(compiler-errors): We should remove this when the old solver goes away;
|
||||
// and all other usages of this function should go through `bound_coroutine_hidden_types`
|
||||
// instead.
|
||||
pub fn coroutine_hidden_types(
|
||||
self,
|
||||
def_id: DefId,
|
||||
|
@ -694,6 +697,33 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
.map(|decl| ty::EarlyBinder::bind(decl.ty))
|
||||
}
|
||||
|
||||
/// Return the set of types that should be taken into account when checking
|
||||
/// trait bounds on a coroutine's internal state. This properly replaces
|
||||
/// `ReErased` with new existential bound lifetimes.
|
||||
pub fn bound_coroutine_hidden_types(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> impl Iterator<Item = ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>>> {
|
||||
let coroutine_layout = self.mir_coroutine_witnesses(def_id);
|
||||
coroutine_layout
|
||||
.as_ref()
|
||||
.map_or_else(|| [].iter(), |l| l.field_tys.iter())
|
||||
.filter(|decl| !decl.ignore_for_traits)
|
||||
.map(move |decl| {
|
||||
let mut vars = vec![];
|
||||
let ty = self.fold_regions(decl.ty, |re, debruijn| {
|
||||
assert_eq!(re, self.lifetimes.re_erased);
|
||||
let var = ty::BoundVar::from_usize(vars.len());
|
||||
vars.push(ty::BoundVariableKind::Region(ty::BrAnon));
|
||||
ty::Region::new_bound(self, debruijn, ty::BoundRegion { var, kind: ty::BrAnon })
|
||||
});
|
||||
ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
|
||||
ty,
|
||||
self.mk_bound_variable_kinds(&vars),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Expands the given impl trait type, stopping if the type is recursive.
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
pub fn try_expand_impl_trait_type(
|
||||
|
@ -998,8 +1028,10 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
|
|||
Some(expanded_ty) => *expanded_ty,
|
||||
None => {
|
||||
if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) {
|
||||
for bty in self.tcx.coroutine_hidden_types(def_id) {
|
||||
let hidden_ty = bty.instantiate(self.tcx, args);
|
||||
for bty in self.tcx.bound_coroutine_hidden_types(def_id) {
|
||||
let hidden_ty = self.tcx.instantiate_bound_regions_with_erased(
|
||||
bty.instantiate(self.tcx, args),
|
||||
);
|
||||
self.fold_ty(hidden_ty);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -879,6 +879,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern } => {
|
||||
self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
|
||||
}
|
||||
|
||||
PatKind::AscribeUserType {
|
||||
ref subpattern,
|
||||
ascription: thir::Ascription { ref annotation, variance: _ },
|
||||
|
|
|
@ -256,6 +256,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
|
|||
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
|
||||
default_irrefutable()
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { .. } => {
|
||||
// FIXME(deref_patterns)
|
||||
// Treat it like a wildcard for now.
|
||||
default_irrefutable()
|
||||
}
|
||||
};
|
||||
|
||||
MatchPair { place, test_case, subpairs, pattern }
|
||||
|
|
|
@ -250,6 +250,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
| PatKind::Variant { .. }
|
||||
| PatKind::Leaf { .. }
|
||||
| PatKind::Deref { .. }
|
||||
| PatKind::DerefPattern { .. }
|
||||
| PatKind::Range { .. }
|
||||
| PatKind::Slice { .. }
|
||||
| PatKind::Array { .. } => {
|
||||
|
@ -310,7 +311,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
}
|
||||
visit::walk_pat(self, pat);
|
||||
}
|
||||
PatKind::Deref { .. } => {
|
||||
PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
|
||||
let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
|
||||
visit::walk_pat(self, pat);
|
||||
self.inside_adt = old_inside_adt;
|
||||
|
|
|
@ -257,6 +257,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
return self.lower_path(qpath, pat.hir_id, pat.span);
|
||||
}
|
||||
|
||||
hir::PatKind::Box(subpattern) if self.tcx.features().deref_patterns => {
|
||||
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) }
|
||||
}
|
||||
hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
|
||||
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
||||
}
|
||||
|
|
|
@ -688,6 +688,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||
self.print_pat(subpattern, depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::DerefPattern { subpattern } => {
|
||||
print_indented!(self, "DerefPattern { ", depth_lvl + 1);
|
||||
print_indented!(self, "subpattern:", depth_lvl + 2);
|
||||
self.print_pat(subpattern, depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::Constant { value } => {
|
||||
print_indented!(self, "Constant {", depth_lvl + 1);
|
||||
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
|
||||
|
|
|
@ -1939,11 +1939,11 @@ impl<'a> Parser<'a> {
|
|||
/// Parse `builtin # ident(args,*)`.
|
||||
fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
|
||||
self.parse_builtin(|this, lo, ident| {
|
||||
if ident.name == sym::offset_of {
|
||||
return Ok(Some(this.parse_expr_offset_of(lo)?));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
Ok(match ident.name {
|
||||
sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
|
||||
sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1978,6 +1978,7 @@ impl<'a> Parser<'a> {
|
|||
ret
|
||||
}
|
||||
|
||||
/// Built-in macro for `offset_of!` expressions.
|
||||
pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
|
||||
let container = self.parse_ty()?;
|
||||
self.expect(&TokenKind::Comma)?;
|
||||
|
@ -2007,6 +2008,15 @@ impl<'a> Parser<'a> {
|
|||
Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
|
||||
}
|
||||
|
||||
/// Built-in macro for type ascription expressions.
|
||||
pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
|
||||
let expr = self.parse_expr()?;
|
||||
self.expect(&token::Comma)?;
|
||||
let ty = self.parse_ty()?;
|
||||
let span = lo.to(self.token.span);
|
||||
Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
|
||||
}
|
||||
|
||||
/// Returns a string literal if the next token is a string literal.
|
||||
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
|
||||
/// and returns `None` if the next token is not literal at all.
|
||||
|
|
|
@ -462,6 +462,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
|||
_ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
|
||||
};
|
||||
}
|
||||
PatKind::DerefPattern { .. } => {
|
||||
// FIXME(deref_patterns): At least detect that `box _` is irrefutable.
|
||||
fields = vec![];
|
||||
arity = 0;
|
||||
ctor = Opaque(OpaqueId::new());
|
||||
}
|
||||
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
|
||||
match ty.kind() {
|
||||
ty::Tuple(fs) => {
|
||||
|
|
|
@ -10,7 +10,7 @@ use rustc_span::Symbol;
|
|||
use stable_mir::abi::Layout;
|
||||
use stable_mir::mir::alloc::AllocId;
|
||||
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
|
||||
use stable_mir::mir::{Mutability, Safety};
|
||||
use stable_mir::mir::{Mutability, Place, ProjectionElem, Safety};
|
||||
use stable_mir::ty::{
|
||||
Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
|
||||
DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
|
||||
|
@ -492,6 +492,50 @@ impl RustcInternal for Layout {
|
|||
}
|
||||
}
|
||||
|
||||
impl RustcInternal for Place {
|
||||
type T<'tcx> = rustc_middle::mir::Place<'tcx>;
|
||||
|
||||
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
||||
rustc_middle::mir::Place {
|
||||
local: rustc_middle::mir::Local::from_usize(self.local),
|
||||
projection: tcx.mk_place_elems(&self.projection.internal(tables, tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RustcInternal for ProjectionElem {
|
||||
type T<'tcx> = rustc_middle::mir::PlaceElem<'tcx>;
|
||||
|
||||
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
||||
match self {
|
||||
ProjectionElem::Deref => rustc_middle::mir::PlaceElem::Deref,
|
||||
ProjectionElem::Field(idx, ty) => {
|
||||
rustc_middle::mir::PlaceElem::Field((*idx).into(), ty.internal(tables, tcx))
|
||||
}
|
||||
ProjectionElem::Index(idx) => rustc_middle::mir::PlaceElem::Index((*idx).into()),
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
rustc_middle::mir::PlaceElem::ConstantIndex {
|
||||
offset: *offset,
|
||||
min_length: *min_length,
|
||||
from_end: *from_end,
|
||||
}
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
rustc_middle::mir::PlaceElem::Subslice { from: *from, to: *to, from_end: *from_end }
|
||||
}
|
||||
ProjectionElem::Downcast(idx) => {
|
||||
rustc_middle::mir::PlaceElem::Downcast(None, idx.internal(tables, tcx))
|
||||
}
|
||||
ProjectionElem::OpaqueCast(ty) => {
|
||||
rustc_middle::mir::PlaceElem::OpaqueCast(ty.internal(tables, tcx))
|
||||
}
|
||||
ProjectionElem::Subtype(ty) => {
|
||||
rustc_middle::mir::PlaceElem::Subtype(ty.internal(tables, tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RustcInternal for &T
|
||||
where
|
||||
T: RustcInternal,
|
||||
|
|
|
@ -14,7 +14,7 @@ pub fn write_smir_pretty<'tcx, W: io::Write>(tcx: TyCtxt<'tcx>, w: &mut W) -> io
|
|||
)?;
|
||||
let _ = run(tcx, || {
|
||||
let items = stable_mir::all_local_items();
|
||||
let _ = items.iter().map(|item| -> io::Result<()> { item.dump(w) }).collect::<Vec<_>>();
|
||||
let _ = items.iter().map(|item| -> io::Result<()> { item.emit_mir(w) }).collect::<Vec<_>>();
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape};
|
|||
use stable_mir::compiler_interface::Context;
|
||||
use stable_mir::mir::alloc::GlobalAlloc;
|
||||
use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
||||
use stable_mir::mir::Body;
|
||||
use stable_mir::mir::{Body, Place};
|
||||
use stable_mir::target::{MachineInfo, MachineSize};
|
||||
use stable_mir::ty::{
|
||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
||||
|
@ -423,7 +423,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
def_ty.instantiate(tables.tcx, args).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String {
|
||||
fn const_pretty(&self, cnst: &stable_mir::ty::Const) -> String {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
cnst.internal(&mut *tables, tcx).to_string()
|
||||
|
@ -434,6 +434,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String {
|
||||
let tables = self.0.borrow_mut();
|
||||
tables.types[ty].to_string()
|
||||
}
|
||||
|
||||
fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
tables.types[ty].kind().stable(&mut *tables)
|
||||
|
@ -654,6 +659,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
let tcx = tables.tcx;
|
||||
id.internal(&mut *tables, tcx).0.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn place_pretty(&self, place: &Place) -> String {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
format!("{:?}", place.internal(&mut *tables, tcx))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
|
||||
|
|
|
@ -674,6 +674,7 @@ symbols! {
|
|||
deref_method,
|
||||
deref_mut,
|
||||
deref_mut_method,
|
||||
deref_patterns,
|
||||
deref_target,
|
||||
derive,
|
||||
derive_const,
|
||||
|
|
|
@ -1621,6 +1621,7 @@ supported_targets! {
|
|||
("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
|
||||
("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf),
|
||||
("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf),
|
||||
("riscv32ima-unknown-none-elf", riscv32ima_unknown_none_elf),
|
||||
("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
|
||||
("riscv32imc-esp-espidf", riscv32imc_esp_espidf),
|
||||
("riscv32imac-esp-espidf", riscv32imac_esp_espidf),
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Target {
|
||||
Target {
|
||||
data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
|
||||
llvm_target: "riscv32".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: None,
|
||||
tier: None,
|
||||
host_tools: None,
|
||||
std: None,
|
||||
},
|
||||
pointer_width: 32,
|
||||
arch: "riscv32".into(),
|
||||
|
||||
options: TargetOptions {
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
cpu: "generic-rv32".into(),
|
||||
max_atomic_width: Some(32),
|
||||
features: "+m,+a".into(),
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
relocation_model: RelocModel::Static,
|
||||
emit_debug_gdb_scripts: false,
|
||||
eh_frame_header: false,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ use rustc_hir::{def_id::DefId, Movability, Mutability};
|
|||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::Goal;
|
||||
use rustc_middle::ty::{
|
||||
self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
};
|
||||
use rustc_span::sym;
|
||||
|
||||
|
@ -73,8 +73,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
|||
|
||||
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
||||
.tcx()
|
||||
.coroutine_hidden_types(def_id)
|
||||
.map(|bty| replace_erased_lifetimes_with_bound_vars(tcx, bty.instantiate(tcx, args)))
|
||||
.bound_coroutine_hidden_types(def_id)
|
||||
.map(|bty| bty.instantiate(tcx, args))
|
||||
.collect()),
|
||||
|
||||
// For `PhantomData<T>`, we pass `T`.
|
||||
|
@ -93,27 +93,6 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> ty::Binder<'tcx, Ty<'tcx>> {
|
||||
debug_assert!(!ty.has_bound_regions());
|
||||
let mut counter = 0;
|
||||
let ty = tcx.fold_regions(ty, |r, current_depth| match r.kind() {
|
||||
ty::ReErased => {
|
||||
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon };
|
||||
counter += 1;
|
||||
ty::Region::new_bound(tcx, current_depth, br)
|
||||
}
|
||||
// All free regions should be erased here.
|
||||
r => bug!("unexpected region: {r:?}"),
|
||||
});
|
||||
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
|
||||
(0..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon)),
|
||||
);
|
||||
ty::Binder::bind_with_vars(ty, bound_vars)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(ecx), ret)]
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||
ecx: &EvalCtxt<'_, 'tcx>,
|
||||
|
@ -241,13 +220,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
|||
// impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
|
||||
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
||||
.tcx()
|
||||
.coroutine_hidden_types(def_id)
|
||||
.map(|bty| {
|
||||
replace_erased_lifetimes_with_bound_vars(
|
||||
ecx.tcx(),
|
||||
bty.instantiate(ecx.tcx(), args),
|
||||
)
|
||||
})
|
||||
.bound_coroutine_hidden_types(def_id)
|
||||
.map(|bty| bty.instantiate(ecx.tcx(), args))
|
||||
.collect()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
|||
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
|
||||
TraitPredicate, Ty, TyCtxt, TypeVisitableExt,
|
||||
TraitPredicate, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_span::def_id::DefId;
|
||||
|
||||
|
@ -1438,10 +1438,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
ty::CoroutineWitness(def_id, args) => {
|
||||
let tcx = self.tcx();
|
||||
stack.extend(tcx.coroutine_hidden_types(def_id).map(|bty| {
|
||||
let ty = bty.instantiate(tcx, args);
|
||||
debug_assert!(!ty.has_bound_regions());
|
||||
ty
|
||||
stack.extend(tcx.bound_coroutine_hidden_types(def_id).map(|bty| {
|
||||
self.infcx.enter_forall_and_leak_universe(bty.instantiate(tcx, args))
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::cell::Cell;
|
|||
use crate::abi::{FnAbi, Layout, LayoutShape};
|
||||
use crate::mir::alloc::{AllocId, GlobalAlloc};
|
||||
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
|
||||
use crate::mir::Body;
|
||||
use crate::mir::{Body, Place};
|
||||
use crate::target::MachineInfo;
|
||||
use crate::ty::{
|
||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
||||
|
@ -126,11 +126,14 @@ pub trait Context {
|
|||
fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty;
|
||||
|
||||
/// Returns literal value of a const as a string.
|
||||
fn const_literal(&self, cnst: &Const) -> String;
|
||||
fn const_pretty(&self, cnst: &Const) -> String;
|
||||
|
||||
/// `Span` of an item
|
||||
fn span_of_an_item(&self, def_id: DefId) -> Span;
|
||||
|
||||
/// Obtain the representation of a type.
|
||||
fn ty_pretty(&self, ty: Ty) -> String;
|
||||
|
||||
/// Obtain the representation of a type.
|
||||
fn ty_kind(&self, ty: Ty) -> TyKind;
|
||||
|
||||
|
@ -205,6 +208,9 @@ pub trait Context {
|
|||
|
||||
/// Get the layout shape.
|
||||
fn layout_shape(&self, id: Layout) -> LayoutShape;
|
||||
|
||||
/// Get a debug string representation of a place.
|
||||
fn place_pretty(&self, place: &Place) -> String;
|
||||
}
|
||||
|
||||
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
|
||||
|
|
|
@ -27,7 +27,6 @@ use crate::compiler_interface::with;
|
|||
pub use crate::crate_def::CrateDef;
|
||||
pub use crate::crate_def::DefId;
|
||||
pub use crate::error::*;
|
||||
use crate::mir::pretty::function_name;
|
||||
use crate::mir::Body;
|
||||
use crate::mir::Mutability;
|
||||
use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
|
||||
|
@ -148,9 +147,8 @@ impl CrateItem {
|
|||
with(|cx| cx.is_foreign_item(self.0))
|
||||
}
|
||||
|
||||
pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
writeln!(w, "{}", function_name(*self))?;
|
||||
self.body().dump(w)
|
||||
pub fn emit_mir<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
self.body().dump(w, &self.name())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator};
|
||||
use crate::mir::pretty::function_body;
|
||||
use crate::ty::{
|
||||
AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
|
||||
VariantIdx,
|
||||
};
|
||||
use crate::{Error, Opaque, Span, Symbol};
|
||||
use std::io;
|
||||
|
||||
/// The SMIR representation of a single function.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Body {
|
||||
|
@ -90,28 +91,9 @@ impl Body {
|
|||
self.locals.iter().enumerate()
|
||||
}
|
||||
|
||||
pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
writeln!(w, "{}", function_body(self))?;
|
||||
self.blocks
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, block)| -> io::Result<()> {
|
||||
writeln!(w, " bb{}: {{", index)?;
|
||||
let _ = block
|
||||
.statements
|
||||
.iter()
|
||||
.map(|statement| -> io::Result<()> {
|
||||
writeln!(w, "{}", pretty_statement(&statement.kind))?;
|
||||
Ok(())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
pretty_terminator(&block.terminator.kind, w)?;
|
||||
writeln!(w, "").unwrap();
|
||||
writeln!(w, " }}").unwrap();
|
||||
Ok(())
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(())
|
||||
/// Emit the body using the provided name for the signature.
|
||||
pub fn dump<W: io::Write>(&self, w: &mut W, fn_name: &str) -> io::Result<()> {
|
||||
function_body(w, self, fn_name)
|
||||
}
|
||||
|
||||
pub fn spread_arg(&self) -> Option<Local> {
|
||||
|
@ -674,7 +656,7 @@ pub enum Operand {
|
|||
Constant(Constant),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct Place {
|
||||
pub local: Local,
|
||||
/// projection out of a place (access a field, deref a pointer, etc)
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::mir::Body;
|
|||
use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
|
||||
use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::io;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum MonoItem {
|
||||
|
@ -157,6 +158,11 @@ impl Instance {
|
|||
pub fn try_const_eval(&self, const_ty: Ty) -> Result<Allocation, Error> {
|
||||
with(|cx| cx.eval_instance(self.def, const_ty))
|
||||
}
|
||||
|
||||
/// Emit the body of this instance if it has one.
|
||||
pub fn emit_mir<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
if let Some(body) = self.body() { body.dump(w, &self.name()) } else { Ok(()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Instance {
|
||||
|
|
|
@ -1,185 +1,193 @@
|
|||
use crate::crate_def::CrateDef;
|
||||
use crate::mir::{Operand, Rvalue, StatementKind, UnwindAction};
|
||||
use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy};
|
||||
use crate::{with, Body, CrateItem, Mutability};
|
||||
use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents};
|
||||
use crate::ty::{Const, IndexedVal, Ty};
|
||||
use crate::{with, Body, Mutability};
|
||||
use fmt::{Display, Formatter};
|
||||
use std::fmt::Debug;
|
||||
use std::io::Write;
|
||||
use std::{io, iter};
|
||||
use std::{fmt, io, iter};
|
||||
|
||||
use super::{AssertMessage, BinOp, TerminatorKind};
|
||||
|
||||
pub fn function_name(item: CrateItem) -> String {
|
||||
let mut pretty_name = String::new();
|
||||
let body = item.body();
|
||||
pretty_name.push_str("fn ");
|
||||
pretty_name.push_str(item.name().as_str());
|
||||
if body.arg_locals().is_empty() {
|
||||
pretty_name.push_str("()");
|
||||
} else {
|
||||
pretty_name.push_str("(");
|
||||
use super::BorrowKind;
|
||||
|
||||
impl Display for Ty {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
with(|ctx| write!(f, "{}", ctx.ty_pretty(*self)))
|
||||
}
|
||||
body.arg_locals().iter().enumerate().for_each(|(index, local)| {
|
||||
pretty_name.push_str(format!("_{}: ", index).as_str());
|
||||
pretty_name.push_str(&pretty_ty(local.ty.kind()));
|
||||
});
|
||||
if !body.arg_locals().is_empty() {
|
||||
pretty_name.push_str(")");
|
||||
}
|
||||
|
||||
impl Debug for Place {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
with(|ctx| write!(f, "{}", ctx.place_pretty(self)))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn function_body<W: Write>(writer: &mut W, body: &Body, name: &str) -> io::Result<()> {
|
||||
write!(writer, "fn {}(", name)?;
|
||||
body.arg_locals()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.try_for_each(|(index, local)| write!(writer, "_{}: {}", index + 1, local.ty))?;
|
||||
write!(writer, ")")?;
|
||||
|
||||
let return_local = body.ret_local();
|
||||
pretty_name.push_str(" -> ");
|
||||
pretty_name.push_str(&pretty_ty(return_local.ty.kind()));
|
||||
pretty_name.push_str(" {");
|
||||
pretty_name
|
||||
writeln!(writer, " -> {} {{", return_local.ty)?;
|
||||
|
||||
body.locals().iter().enumerate().try_for_each(|(index, local)| -> io::Result<()> {
|
||||
if index == 0 || index > body.arg_count {
|
||||
writeln!(writer, " let {}_{}: {};", pretty_mut(local.mutability), index, local.ty)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})?;
|
||||
|
||||
body.var_debug_info.iter().try_for_each(|info| {
|
||||
let content = match &info.value {
|
||||
VarDebugInfoContents::Place(place) => {
|
||||
format!("{place:?}")
|
||||
}
|
||||
VarDebugInfoContents::Const(constant) => pretty_const(&constant.const_),
|
||||
};
|
||||
writeln!(writer, " debug {} => {};", info.name, content)
|
||||
})?;
|
||||
|
||||
body.blocks
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, block)| -> io::Result<()> {
|
||||
writeln!(writer, " bb{}: {{", index)?;
|
||||
let _ = block
|
||||
.statements
|
||||
.iter()
|
||||
.map(|statement| -> io::Result<()> {
|
||||
pretty_statement(writer, &statement.kind)?;
|
||||
Ok(())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
pretty_terminator(writer, &block.terminator.kind)?;
|
||||
writeln!(writer, " }}").unwrap();
|
||||
Ok(())
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
writeln!(writer, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn function_body(body: &Body) -> String {
|
||||
let mut pretty_body = String::new();
|
||||
body.inner_locals().iter().enumerate().for_each(|(index, local)| {
|
||||
pretty_body.push_str(" ");
|
||||
pretty_body.push_str(format!("let {}", ret_mutability(&local.mutability)).as_str());
|
||||
pretty_body.push_str(format!("_{}: ", index).as_str());
|
||||
pretty_body.push_str(format!("{}", pretty_ty(local.ty.kind())).as_str());
|
||||
pretty_body.push_str(";\n");
|
||||
});
|
||||
pretty_body.push_str("}");
|
||||
pretty_body
|
||||
}
|
||||
|
||||
pub fn ret_mutability(mutability: &Mutability) -> String {
|
||||
match mutability {
|
||||
Mutability::Not => "".to_string(),
|
||||
Mutability::Mut => "mut ".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pretty_statement(statement: &StatementKind) -> String {
|
||||
let mut pretty = String::new();
|
||||
fn pretty_statement<W: Write>(writer: &mut W, statement: &StatementKind) -> io::Result<()> {
|
||||
match statement {
|
||||
StatementKind::Assign(place, rval) => {
|
||||
pretty.push_str(format!(" _{} = ", place.local).as_str());
|
||||
pretty.push_str(format!("{}", &pretty_rvalue(rval)).as_str());
|
||||
write!(writer, " {:?} = ", place)?;
|
||||
pretty_rvalue(writer, rval)?;
|
||||
writeln!(writer, ";")
|
||||
}
|
||||
// FIXME: Add rest of the statements
|
||||
StatementKind::FakeRead(_, _) => {
|
||||
return String::from("StatementKind::FakeRead:Unimplemented");
|
||||
StatementKind::FakeRead(cause, place) => {
|
||||
writeln!(writer, "FakeRead({cause:?}, {place:?});")
|
||||
}
|
||||
StatementKind::SetDiscriminant { .. } => {
|
||||
return String::from("StatementKind::SetDiscriminant:Unimplemented");
|
||||
StatementKind::SetDiscriminant { place, variant_index } => {
|
||||
writeln!(writer, "discriminant({place:?} = {};", variant_index.to_index())
|
||||
}
|
||||
StatementKind::Deinit(_) => return String::from("StatementKind::Deinit:Unimplemented"),
|
||||
StatementKind::StorageLive(_) => {
|
||||
return String::from("StatementKind::StorageLive:Unimplemented");
|
||||
StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"),
|
||||
StatementKind::StorageLive(local) => {
|
||||
writeln!(writer, "StorageLive(_{local});")
|
||||
}
|
||||
StatementKind::StorageDead(_) => {
|
||||
return String::from("StatementKind::StorageDead:Unimplemented");
|
||||
StatementKind::StorageDead(local) => {
|
||||
writeln!(writer, "StorageDead(_{local});")
|
||||
}
|
||||
StatementKind::Retag(_, _) => return String::from("StatementKind::Retag:Unimplemented"),
|
||||
StatementKind::PlaceMention(_) => {
|
||||
return String::from("StatementKind::PlaceMention:Unimplemented");
|
||||
}
|
||||
StatementKind::AscribeUserType { .. } => {
|
||||
return String::from("StatementKind::AscribeUserType:Unimplemented");
|
||||
}
|
||||
StatementKind::Coverage(_) => return String::from("StatementKind::Coverage:Unimplemented"),
|
||||
StatementKind::Intrinsic(_) => {
|
||||
return String::from("StatementKind::Intrinsic:Unimplemented");
|
||||
StatementKind::Retag(kind, place) => writeln!(writer, "Retag({kind:?}, {place:?});"),
|
||||
StatementKind::PlaceMention(place) => {
|
||||
writeln!(writer, "PlaceMention({place:?};")
|
||||
}
|
||||
StatementKind::ConstEvalCounter => {
|
||||
return String::from("StatementKind::ConstEvalCounter:Unimplemented");
|
||||
writeln!(writer, "ConstEvalCounter;")
|
||||
}
|
||||
StatementKind::Nop => writeln!(writer, "nop;"),
|
||||
StatementKind::AscribeUserType { .. }
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::Intrinsic(_) => {
|
||||
// FIX-ME: Make them pretty.
|
||||
writeln!(writer, "{statement:?};")
|
||||
}
|
||||
StatementKind::Nop => return String::from("StatementKind::Nop:Unimplemented"),
|
||||
}
|
||||
pretty
|
||||
}
|
||||
|
||||
pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> {
|
||||
write!(w, "{}", pretty_terminator_head(terminator))?;
|
||||
fn pretty_terminator<W: Write>(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> {
|
||||
pretty_terminator_head(writer, terminator)?;
|
||||
let successors = terminator.successors();
|
||||
let successor_count = successors.len();
|
||||
let labels = pretty_successor_labels(terminator);
|
||||
|
||||
let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_)));
|
||||
let fmt_unwind = |fmt: &mut dyn Write| -> io::Result<()> {
|
||||
write!(fmt, "unwind ")?;
|
||||
let fmt_unwind = |w: &mut W| -> io::Result<()> {
|
||||
write!(w, "unwind ")?;
|
||||
match terminator.unwind() {
|
||||
None | Some(UnwindAction::Cleanup(_)) => unreachable!(),
|
||||
Some(UnwindAction::Continue) => write!(fmt, "continue"),
|
||||
Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"),
|
||||
Some(UnwindAction::Terminate) => write!(fmt, "terminate"),
|
||||
Some(UnwindAction::Continue) => write!(w, "continue"),
|
||||
Some(UnwindAction::Unreachable) => write!(w, "unreachable"),
|
||||
Some(UnwindAction::Terminate) => write!(w, "terminate"),
|
||||
}
|
||||
};
|
||||
|
||||
match (successor_count, show_unwind) {
|
||||
(0, false) => Ok(()),
|
||||
(0, false) => {}
|
||||
(0, true) => {
|
||||
write!(w, " -> ")?;
|
||||
fmt_unwind(w)?;
|
||||
Ok(())
|
||||
}
|
||||
(1, false) => {
|
||||
write!(w, " -> {:?}", successors[0])?;
|
||||
Ok(())
|
||||
write!(writer, " -> ")?;
|
||||
fmt_unwind(writer)?;
|
||||
}
|
||||
(1, false) => write!(writer, " -> bb{:?}", successors[0])?,
|
||||
_ => {
|
||||
write!(w, " -> [")?;
|
||||
write!(writer, " -> [")?;
|
||||
for (i, target) in successors.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(w, ", ")?;
|
||||
write!(writer, ", ")?;
|
||||
}
|
||||
write!(w, "{}: bb{:?}", labels[i], target)?;
|
||||
write!(writer, "{}: bb{:?}", labels[i], target)?;
|
||||
}
|
||||
if show_unwind {
|
||||
write!(w, ", ")?;
|
||||
fmt_unwind(w)?;
|
||||
write!(writer, ", ")?;
|
||||
fmt_unwind(writer)?;
|
||||
}
|
||||
write!(w, "]")
|
||||
write!(writer, "]")?;
|
||||
}
|
||||
}?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
writeln!(writer, ";")
|
||||
}
|
||||
|
||||
pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String {
|
||||
fn pretty_terminator_head<W: Write>(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> {
|
||||
use self::TerminatorKind::*;
|
||||
let mut pretty = String::new();
|
||||
const INDENT: &'static str = " ";
|
||||
match terminator {
|
||||
Goto { .. } => format!(" goto"),
|
||||
Goto { .. } => write!(writer, "{INDENT}goto"),
|
||||
SwitchInt { discr, .. } => {
|
||||
format!(" switchInt(_{})", pretty_operand(discr))
|
||||
write!(writer, "{INDENT}switchInt({})", pretty_operand(discr))
|
||||
}
|
||||
Resume => format!(" resume"),
|
||||
Abort => format!(" abort"),
|
||||
Return => format!(" return"),
|
||||
Unreachable => format!(" unreachable"),
|
||||
Drop { place, .. } => format!(" drop(_{:?})", place.local),
|
||||
Resume => write!(writer, "{INDENT}resume"),
|
||||
Abort => write!(writer, "{INDENT}abort"),
|
||||
Return => write!(writer, "{INDENT}return"),
|
||||
Unreachable => write!(writer, "{INDENT}unreachable"),
|
||||
Drop { place, .. } => write!(writer, "{INDENT}drop({:?})", place),
|
||||
Call { func, args, destination, .. } => {
|
||||
pretty.push_str(" ");
|
||||
pretty.push_str(format!("_{} = ", destination.local).as_str());
|
||||
pretty.push_str(&pretty_operand(func));
|
||||
pretty.push_str("(");
|
||||
args.iter().enumerate().for_each(|(i, arg)| {
|
||||
if i > 0 {
|
||||
pretty.push_str(", ");
|
||||
}
|
||||
pretty.push_str(&pretty_operand(arg));
|
||||
});
|
||||
pretty.push_str(")");
|
||||
pretty
|
||||
write!(writer, "{INDENT}{:?} = {}(", destination, pretty_operand(func))?;
|
||||
let mut args_iter = args.iter();
|
||||
args_iter.next().map_or(Ok(()), |arg| write!(writer, "{}", pretty_operand(arg)))?;
|
||||
args_iter.try_for_each(|arg| write!(writer, ", {}", pretty_operand(arg)))?;
|
||||
write!(writer, ")")
|
||||
}
|
||||
Assert { cond, expected, msg, target: _, unwind: _ } => {
|
||||
pretty.push_str(" assert(");
|
||||
write!(writer, "{INDENT}assert(")?;
|
||||
if !expected {
|
||||
pretty.push_str("!");
|
||||
write!(writer, "!")?;
|
||||
}
|
||||
pretty.push_str(format!("{} bool),", &pretty_operand(cond)).as_str());
|
||||
pretty.push_str(&pretty_assert_message(msg));
|
||||
pretty.push_str(")");
|
||||
pretty
|
||||
write!(writer, "{}, ", &pretty_operand(cond))?;
|
||||
pretty_assert_message(writer, msg)?;
|
||||
write!(writer, ")")
|
||||
}
|
||||
InlineAsm { .. } => todo!(),
|
||||
InlineAsm { .. } => write!(writer, "{INDENT}InlineAsm"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
|
||||
fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
|
||||
use self::TerminatorKind::*;
|
||||
match terminator {
|
||||
Resume | Abort | Return | Unreachable => vec![],
|
||||
|
@ -201,283 +209,174 @@ pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
|
|||
vec!["success".into(), "unwind".into()]
|
||||
}
|
||||
Assert { unwind: _, .. } => vec!["success".into()],
|
||||
InlineAsm { .. } => todo!(),
|
||||
InlineAsm { destination: Some(_), .. } => vec!["goto".into(), "unwind".into()],
|
||||
InlineAsm { destination: None, .. } => vec!["unwind".into()],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pretty_assert_message(msg: &AssertMessage) -> String {
|
||||
let mut pretty = String::new();
|
||||
fn pretty_assert_message<W: Write>(writer: &mut W, msg: &AssertMessage) -> io::Result<()> {
|
||||
match msg {
|
||||
AssertMessage::BoundsCheck { len, index } => {
|
||||
let pretty_len = pretty_operand(len);
|
||||
let pretty_index = pretty_operand(index);
|
||||
pretty.push_str(format!("\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}").as_str());
|
||||
pretty
|
||||
write!(
|
||||
writer,
|
||||
"\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}"
|
||||
)
|
||||
}
|
||||
AssertMessage::Overflow(BinOp::Add, l, r) => {
|
||||
let pretty_l = pretty_operand(l);
|
||||
let pretty_r = pretty_operand(r);
|
||||
pretty.push_str(format!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||
pretty
|
||||
write!(
|
||||
writer,
|
||||
"\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
|
||||
)
|
||||
}
|
||||
AssertMessage::Overflow(BinOp::Sub, l, r) => {
|
||||
let pretty_l = pretty_operand(l);
|
||||
let pretty_r = pretty_operand(r);
|
||||
pretty.push_str(format!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||
pretty
|
||||
write!(
|
||||
writer,
|
||||
"\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
|
||||
)
|
||||
}
|
||||
AssertMessage::Overflow(BinOp::Mul, l, r) => {
|
||||
let pretty_l = pretty_operand(l);
|
||||
let pretty_r = pretty_operand(r);
|
||||
pretty.push_str(format!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||
pretty
|
||||
write!(
|
||||
writer,
|
||||
"\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
|
||||
)
|
||||
}
|
||||
AssertMessage::Overflow(BinOp::Div, l, r) => {
|
||||
let pretty_l = pretty_operand(l);
|
||||
let pretty_r = pretty_operand(r);
|
||||
pretty.push_str(format!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||
pretty
|
||||
write!(
|
||||
writer,
|
||||
"\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
|
||||
)
|
||||
}
|
||||
AssertMessage::Overflow(BinOp::Rem, l, r) => {
|
||||
let pretty_l = pretty_operand(l);
|
||||
let pretty_r = pretty_operand(r);
|
||||
pretty.push_str(format!("\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||
pretty
|
||||
write!(
|
||||
writer,
|
||||
"\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
|
||||
)
|
||||
}
|
||||
AssertMessage::Overflow(BinOp::Shr, _, r) => {
|
||||
let pretty_r = pretty_operand(r);
|
||||
pretty.push_str(
|
||||
format!("\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}")
|
||||
.as_str(),
|
||||
);
|
||||
pretty
|
||||
write!(writer, "\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}")
|
||||
}
|
||||
AssertMessage::Overflow(BinOp::Shl, _, r) => {
|
||||
let pretty_r = pretty_operand(r);
|
||||
pretty.push_str(
|
||||
format!("\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}")
|
||||
.as_str(),
|
||||
);
|
||||
pretty
|
||||
write!(writer, "\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}")
|
||||
}
|
||||
AssertMessage::Overflow(op, _, _) => unreachable!("`{:?}` cannot overflow", op),
|
||||
AssertMessage::OverflowNeg(op) => {
|
||||
let pretty_op = pretty_operand(op);
|
||||
pretty.push_str(
|
||||
format!("\"attempt to negate `{{}}`, which would overflow\", {pretty_op}").as_str(),
|
||||
);
|
||||
pretty
|
||||
write!(writer, "\"attempt to negate `{{}}`, which would overflow\", {pretty_op}")
|
||||
}
|
||||
AssertMessage::DivisionByZero(op) => {
|
||||
let pretty_op = pretty_operand(op);
|
||||
pretty.push_str(format!("\"attempt to divide `{{}}` by zero\", {pretty_op}").as_str());
|
||||
pretty
|
||||
write!(writer, "\"attempt to divide `{{}}` by zero\", {pretty_op}")
|
||||
}
|
||||
AssertMessage::RemainderByZero(op) => {
|
||||
let pretty_op = pretty_operand(op);
|
||||
pretty.push_str(
|
||||
format!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}").as_str(),
|
||||
);
|
||||
pretty
|
||||
write!(
|
||||
writer,
|
||||
"\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}"
|
||||
)
|
||||
}
|
||||
AssertMessage::MisalignedPointerDereference { required, found } => {
|
||||
let pretty_required = pretty_operand(required);
|
||||
let pretty_found = pretty_operand(found);
|
||||
pretty.push_str(format!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}").as_str());
|
||||
pretty
|
||||
write!(
|
||||
writer,
|
||||
"\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}"
|
||||
)
|
||||
}
|
||||
AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => {
|
||||
msg.description().unwrap().to_string()
|
||||
write!(writer, "{}", msg.description().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pretty_operand(operand: &Operand) -> String {
|
||||
let mut pretty = String::new();
|
||||
fn pretty_operand(operand: &Operand) -> String {
|
||||
match operand {
|
||||
Operand::Copy(copy) => {
|
||||
pretty.push_str("");
|
||||
pretty.push_str(format!("{}", copy.local).as_str());
|
||||
format!("{:?}", copy)
|
||||
}
|
||||
Operand::Move(mv) => {
|
||||
pretty.push_str("move ");
|
||||
pretty.push_str(format!("_{}", mv.local).as_str());
|
||||
}
|
||||
Operand::Constant(cnst) => {
|
||||
pretty.push_str("const ");
|
||||
pretty.push_str(with(|cx| cx.const_literal(&cnst.literal)).as_str());
|
||||
format!("move {:?}", mv)
|
||||
}
|
||||
Operand::Constant(cnst) => pretty_const(&cnst.literal),
|
||||
}
|
||||
pretty
|
||||
}
|
||||
|
||||
pub fn pretty_rvalue(rval: &Rvalue) -> String {
|
||||
let mut pretty = String::new();
|
||||
fn pretty_const(literal: &Const) -> String {
|
||||
with(|cx| cx.const_pretty(&literal))
|
||||
}
|
||||
|
||||
fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
|
||||
match rval {
|
||||
Rvalue::AddressOf(muta, addr) => {
|
||||
pretty.push_str("&raw ");
|
||||
pretty.push_str(&ret_mutability(muta));
|
||||
pretty.push_str(format!("(*_{})", addr.local).as_str());
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
write!(writer, "&raw {}(*{:?})", &pretty_mut(*mutability), place)
|
||||
}
|
||||
Rvalue::Aggregate(aggregatekind, operands) => {
|
||||
pretty.push_str(format!("{:#?}", aggregatekind).as_str());
|
||||
pretty.push_str("(");
|
||||
operands.iter().enumerate().for_each(|(i, op)| {
|
||||
pretty.push_str(&pretty_operand(op));
|
||||
if i != operands.len() - 1 {
|
||||
pretty.push_str(", ");
|
||||
}
|
||||
});
|
||||
pretty.push_str(")");
|
||||
Rvalue::Aggregate(aggregate_kind, operands) => {
|
||||
// FIXME: Add pretty_aggregate function that returns a pretty string
|
||||
write!(writer, "{aggregate_kind:?} (")?;
|
||||
let mut op_iter = operands.iter();
|
||||
op_iter.next().map_or(Ok(()), |op| write!(writer, "{}", pretty_operand(op)))?;
|
||||
op_iter.try_for_each(|op| write!(writer, ", {}", pretty_operand(op)))?;
|
||||
write!(writer, ")")
|
||||
}
|
||||
Rvalue::BinaryOp(bin, op, op2) => {
|
||||
pretty.push_str(&pretty_operand(op));
|
||||
pretty.push_str(" ");
|
||||
pretty.push_str(format!("{:#?}", bin).as_str());
|
||||
pretty.push_str(" ");
|
||||
pretty.push_str(&pretty_operand(op2));
|
||||
Rvalue::BinaryOp(bin, op1, op2) => {
|
||||
write!(writer, "{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
|
||||
}
|
||||
Rvalue::Cast(_, op, ty) => {
|
||||
pretty.push_str(&pretty_operand(op));
|
||||
pretty.push_str(" as ");
|
||||
pretty.push_str(&pretty_ty(ty.kind()));
|
||||
write!(writer, "{} as {}", pretty_operand(op), ty)
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(bin, op1, op2) => {
|
||||
pretty.push_str(&pretty_operand(op1));
|
||||
pretty.push_str(" ");
|
||||
pretty.push_str(format!("{:#?}", bin).as_str());
|
||||
pretty.push_str(" ");
|
||||
pretty.push_str(&pretty_operand(op2));
|
||||
write!(writer, "Checked{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
|
||||
}
|
||||
Rvalue::CopyForDeref(deref) => {
|
||||
pretty.push_str("CopyForDeref");
|
||||
pretty.push_str(format!("{}", deref.local).as_str());
|
||||
write!(writer, "CopyForDeref({:?})", deref)
|
||||
}
|
||||
Rvalue::Discriminant(place) => {
|
||||
pretty.push_str("discriminant");
|
||||
pretty.push_str(format!("{}", place.local).as_str());
|
||||
write!(writer, "discriminant({:?})", place)
|
||||
}
|
||||
Rvalue::Len(len) => {
|
||||
pretty.push_str("len");
|
||||
pretty.push_str(format!("{}", len.local).as_str());
|
||||
write!(writer, "len({:?})", len)
|
||||
}
|
||||
Rvalue::Ref(_, borrowkind, place) => {
|
||||
pretty.push_str("ref");
|
||||
pretty.push_str(format!("{:#?}", borrowkind).as_str());
|
||||
pretty.push_str(format!("{}", place.local).as_str());
|
||||
let kind = match borrowkind {
|
||||
BorrowKind::Shared => "&",
|
||||
BorrowKind::Fake => "&fake ",
|
||||
BorrowKind::Mut { .. } => "&mut ",
|
||||
};
|
||||
write!(writer, "{kind}{:?}", place)
|
||||
}
|
||||
Rvalue::Repeat(op, cnst) => {
|
||||
pretty.push_str(&pretty_operand(op));
|
||||
pretty.push_str(" ");
|
||||
pretty.push_str(&pretty_ty(cnst.ty().kind()));
|
||||
write!(writer, "{} \" \" {}", &pretty_operand(op), cnst.ty())
|
||||
}
|
||||
Rvalue::ShallowInitBox(_, _) => (),
|
||||
Rvalue::ShallowInitBox(_, _) => Ok(()),
|
||||
Rvalue::ThreadLocalRef(item) => {
|
||||
pretty.push_str("thread_local_ref");
|
||||
pretty.push_str(format!("{:#?}", item).as_str());
|
||||
write!(writer, "thread_local_ref{:?}", item)
|
||||
}
|
||||
Rvalue::NullaryOp(nul, ty) => {
|
||||
pretty.push_str(format!("{:#?}", nul).as_str());
|
||||
pretty.push_str(&pretty_ty(ty.kind()));
|
||||
pretty.push_str(" ");
|
||||
write!(writer, "{:?} {} \" \"", nul, ty)
|
||||
}
|
||||
Rvalue::UnaryOp(un, op) => {
|
||||
pretty.push_str(&pretty_operand(op));
|
||||
pretty.push_str(" ");
|
||||
pretty.push_str(format!("{:#?}", un).as_str());
|
||||
write!(writer, "{} \" \" {:?}", pretty_operand(op), un)
|
||||
}
|
||||
Rvalue::Use(op) => pretty.push_str(&pretty_operand(op)),
|
||||
Rvalue::Use(op) => write!(writer, "{}", pretty_operand(op)),
|
||||
}
|
||||
pretty
|
||||
}
|
||||
|
||||
pub fn pretty_ty(ty: TyKind) -> String {
|
||||
let mut pretty = String::new();
|
||||
match ty {
|
||||
TyKind::RigidTy(rigid_ty) => match rigid_ty {
|
||||
RigidTy::Bool => "bool".to_string(),
|
||||
RigidTy::Char => "char".to_string(),
|
||||
RigidTy::Int(i) => match i {
|
||||
IntTy::Isize => "isize".to_string(),
|
||||
IntTy::I8 => "i8".to_string(),
|
||||
IntTy::I16 => "i16".to_string(),
|
||||
IntTy::I32 => "i32".to_string(),
|
||||
IntTy::I64 => "i64".to_string(),
|
||||
IntTy::I128 => "i128".to_string(),
|
||||
},
|
||||
RigidTy::Uint(u) => match u {
|
||||
UintTy::Usize => "usize".to_string(),
|
||||
UintTy::U8 => "u8".to_string(),
|
||||
UintTy::U16 => "u16".to_string(),
|
||||
UintTy::U32 => "u32".to_string(),
|
||||
UintTy::U64 => "u64".to_string(),
|
||||
UintTy::U128 => "u128".to_string(),
|
||||
},
|
||||
RigidTy::Float(f) => match f {
|
||||
FloatTy::F32 => "f32".to_string(),
|
||||
FloatTy::F64 => "f64".to_string(),
|
||||
},
|
||||
RigidTy::Adt(def, _) => {
|
||||
format!("{:#?}", with(|cx| cx.def_ty(def.0)))
|
||||
}
|
||||
RigidTy::Str => "str".to_string(),
|
||||
RigidTy::Array(ty, len) => {
|
||||
format!("[{}; {}]", pretty_ty(ty.kind()), with(|cx| cx.const_literal(&len)))
|
||||
}
|
||||
RigidTy::Slice(ty) => {
|
||||
format!("[{}]", pretty_ty(ty.kind()))
|
||||
}
|
||||
RigidTy::RawPtr(ty, mutability) => {
|
||||
pretty.push_str("*");
|
||||
match mutability {
|
||||
Mutability::Not => pretty.push_str("const "),
|
||||
Mutability::Mut => pretty.push_str("mut "),
|
||||
}
|
||||
pretty.push_str(&pretty_ty(ty.kind()));
|
||||
pretty
|
||||
}
|
||||
RigidTy::Ref(_, ty, mutability) => match mutability {
|
||||
Mutability::Not => format!("&{}", pretty_ty(ty.kind())),
|
||||
Mutability::Mut => format!("&mut {}", pretty_ty(ty.kind())),
|
||||
},
|
||||
RigidTy::FnDef(_, _) => format!("{:#?}", rigid_ty),
|
||||
RigidTy::FnPtr(_) => format!("{:#?}", rigid_ty),
|
||||
RigidTy::Closure(_, _) => format!("{:#?}", rigid_ty),
|
||||
RigidTy::Coroutine(_, _, _) => format!("{:#?}", rigid_ty),
|
||||
RigidTy::Dynamic(data, region, repr) => {
|
||||
// FIXME: Fix binder printing, it looks ugly now
|
||||
pretty.push_str("(");
|
||||
match repr {
|
||||
DynKind::Dyn => pretty.push_str("dyn "),
|
||||
DynKind::DynStar => pretty.push_str("dyn* "),
|
||||
}
|
||||
pretty.push_str(format!("{:#?}", data).as_str());
|
||||
pretty.push_str(format!(" + {:#?} )", region).as_str());
|
||||
pretty
|
||||
}
|
||||
RigidTy::Never => "!".to_string(),
|
||||
RigidTy::Tuple(tuple) => {
|
||||
if tuple.is_empty() {
|
||||
"()".to_string()
|
||||
} else {
|
||||
let mut tuple_str = String::new();
|
||||
tuple_str.push_str("(");
|
||||
tuple.iter().enumerate().for_each(|(i, ty)| {
|
||||
tuple_str.push_str(&pretty_ty(ty.kind()));
|
||||
if i != tuple.len() - 1 {
|
||||
tuple_str.push_str(", ");
|
||||
}
|
||||
});
|
||||
tuple_str.push_str(")");
|
||||
tuple_str
|
||||
}
|
||||
}
|
||||
_ => format!("{:#?}", rigid_ty),
|
||||
},
|
||||
TyKind::Alias(_, _) => format!("{:#?}", ty),
|
||||
TyKind::Param(param_ty) => {
|
||||
format!("{:#?}", param_ty.name)
|
||||
}
|
||||
TyKind::Bound(_, _) => format!("{:#?}", ty),
|
||||
fn pretty_mut(mutability: Mutability) -> &'static str {
|
||||
match mutability {
|
||||
Mutability::Not => " ",
|
||||
Mutability::Mut => "mut ",
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue