Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2025-02-03 05:02:55 +00:00
commit 45c3b3d480
293 changed files with 2006 additions and 2602 deletions

View file

@ -418,10 +418,10 @@ fn compute_hir_hash(
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
let sess = tcx.sess;
// Queries that borrow `resolver_for_lowering`.
tcx.ensure_with_value().output_filenames(());
tcx.ensure_with_value().early_lint_checks(());
tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE);
tcx.ensure_with_value().get_lang_items(());
tcx.ensure_done().output_filenames(());
tcx.ensure_done().early_lint_checks(());
tcx.ensure_done().debugger_visualizers(LOCAL_CRATE);
tcx.ensure_done().get_lang_items(());
let (mut resolver, krate) = tcx.resolver_for_lowering().steal();
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);

View file

@ -101,16 +101,6 @@ impl PartialConstStability {
}
}
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
#[derive(HashStable_Generic)]
pub enum AllowedThroughUnstableModules {
/// This does not get a deprecation warning. We still generally would prefer people to use the
/// fully stable path, and a warning will likely be emitted in the future.
WithoutDeprecation,
/// Emit the given deprecation warning.
WithDeprecation(Symbol),
}
/// The available stability levels.
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
#[derive(HashStable_Generic)]
@ -147,8 +137,9 @@ pub enum StabilityLevel {
Stable {
/// Rust release which stabilized this feature.
since: StableSince,
/// This is `Some` if this item allowed to be referred to on stable via unstable modules.
allowed_through_unstable_modules: Option<AllowedThroughUnstableModules>,
/// This is `Some` if this item allowed to be referred to on stable via unstable modules;
/// the `Symbol` is the deprecation message printed in that case.
allowed_through_unstable_modules: Option<Symbol>,
},
}

View file

@ -6,12 +6,12 @@ use rustc_ast::MetaItem;
use rustc_ast::attr::AttributeExt;
use rustc_ast_pretty::pprust;
use rustc_attr_data_structures::{
AllowedThroughUnstableModules, ConstStability, DefaultBodyStability, Stability, StabilityLevel,
StableSince, UnstableReason, VERSION_PLACEHOLDER,
ConstStability, DefaultBodyStability, Stability, StabilityLevel, StableSince, UnstableReason,
VERSION_PLACEHOLDER,
};
use rustc_errors::ErrorGuaranteed;
use rustc_session::Session;
use rustc_span::{Span, Symbol, sym};
use rustc_span::{Span, Symbol, kw, sym};
use crate::attributes::util::UnsupportedLiteralReason;
use crate::{parse_version, session_diagnostics};
@ -29,10 +29,14 @@ pub fn find_stability(
for attr in attrs {
match attr.name_or_empty() {
sym::rustc_allowed_through_unstable_modules => {
allowed_through_unstable_modules = Some(match attr.value_str() {
Some(msg) => AllowedThroughUnstableModules::WithDeprecation(msg),
None => AllowedThroughUnstableModules::WithoutDeprecation,
})
// The value is mandatory, but avoid ICEs in case such code reaches this function.
allowed_through_unstable_modules = Some(attr.value_str().unwrap_or_else(|| {
sess.dcx().span_delayed_bug(
item_sp,
"`#[rustc_allowed_through_unstable_modules]` without deprecation message",
);
kw::Empty
}))
}
sym::unstable => {
if stab.is_some() {

View file

@ -92,9 +92,6 @@ borrowck_lifetime_constraints_error =
borrowck_limitations_implies_static =
due to current limitations in the borrow checker, this implies a `'static` lifetime
borrowck_long_type_consider_verbose = consider using `--verbose` to print the full type name to the console
borrowck_long_type_full_path = the full type name has been written to '{$path}'
borrowck_move_closure_suggestion =
consider adding 'move' keyword before the nested closure

View file

@ -289,8 +289,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
None => "value".to_owned(),
};
if needs_note {
let mut path = None;
let ty = self.infcx.tcx.short_ty_string(ty, &mut path);
let ty = self.infcx.tcx.short_string(ty, err.long_ty_path());
if let Some(local) = place.as_local() {
let span = self.body.local_decls[local].source_info.span;
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
@ -306,11 +305,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
place: &note_msg,
});
};
if let Some(path) = path {
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
path: path.display().to_string(),
});
}
}
if let UseSpans::FnSelfUse {

View file

@ -248,7 +248,98 @@ impl<'tcx> BorrowExplanation<'tcx> {
);
err.span_label(body.source_info(drop_loc).span, message);
if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
struct FindLetExpr<'hir> {
span: Span,
result: Option<(Span, &'hir hir::Pat<'hir>, &'hir hir::Expr<'hir>)>,
tcx: TyCtxt<'hir>,
}
impl<'hir> rustc_hir::intravisit::Visitor<'hir> for FindLetExpr<'hir> {
type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
if let hir::ExprKind::If(cond, _conseq, _alt)
| hir::ExprKind::Loop(
hir::Block {
expr:
Some(&hir::Expr {
kind: hir::ExprKind::If(cond, _conseq, _alt),
..
}),
..
},
_,
hir::LoopSource::While,
_,
) = expr.kind
&& let hir::ExprKind::Let(hir::LetExpr {
init: let_expr_init,
span: let_expr_span,
pat: let_expr_pat,
..
}) = cond.kind
&& let_expr_init.span.contains(self.span)
{
self.result =
Some((*let_expr_span, let_expr_pat, let_expr_init))
} else {
hir::intravisit::walk_expr(self, expr);
}
}
}
if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info()
&& let hir::Node::Expr(expr) = tcx.hir_node(if_then)
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
&& let hir::ExprKind::Let(&hir::LetExpr {
span: _,
pat,
init,
// FIXME(#101728): enable rewrite when type ascription is
// stabilized again.
ty: None,
recovered: _,
}) = cond.kind
&& pat.span.can_be_used_for_suggestions()
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
{
suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
} else if let Some((old, new)) = multiple_borrow_span
&& let def_id = body.source.def_id()
&& let Some(node) = tcx.hir().get_if_local(def_id)
&& let Some(body_id) = node.body_id()
&& let hir_body = tcx.hir().body(body_id)
&& let mut expr_finder = (FindLetExpr { span: old, result: None, tcx })
&& let Some((let_expr_span, let_expr_pat, let_expr_init)) = {
expr_finder.visit_expr(hir_body.value);
expr_finder.result
}
&& !let_expr_span.contains(new)
{
// #133941: The `old` expression is at the conditional part of an
// if/while let expression. Adding a semicolon won't work.
// Instead, try suggesting the `matches!` macro or a temporary.
if let_expr_pat
.walk_short(|pat| !matches!(pat.kind, hir::PatKind::Binding(..)))
{
if let Ok(pat_snippet) =
tcx.sess.source_map().span_to_snippet(let_expr_pat.span)
&& let Ok(init_snippet) =
tcx.sess.source_map().span_to_snippet(let_expr_init.span)
{
err.span_suggestion_verbose(
let_expr_span,
"consider using the `matches!` macro",
format!("matches!({init_snippet}, {pat_snippet})"),
Applicability::MaybeIncorrect,
);
} else {
err.note("consider using the `matches!` macro");
}
}
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
if info.tail_result_is_ignored {
// #85581: If the first mutable borrow's scope contains
// the second borrow, this suggestion isn't helpful.
@ -281,23 +372,6 @@ impl<'tcx> BorrowExplanation<'tcx> {
Applicability::MaybeIncorrect,
);
};
} else if let &LocalInfo::IfThenRescopeTemp { if_then } =
local_decl.local_info()
&& let hir::Node::Expr(expr) = tcx.hir_node(if_then)
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
&& let hir::ExprKind::Let(&hir::LetExpr {
span: _,
pat,
init,
// FIXME(#101728): enable rewrite when type ascription is
// stabilized again.
ty: None,
recovered: _,
}) = cond.kind
&& pat.span.can_be_used_for_suggestions()
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
{
suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
}
}
}

View file

@ -4,7 +4,7 @@ use std::collections::BTreeMap;
use rustc_abi::{FieldIdx, VariantIdx};
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan};
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::{self as hir, CoroutineKind, LangItem};
use rustc_index::IndexSlice;
@ -29,7 +29,7 @@ use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{
FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
};
use tracing::debug;
@ -1434,17 +1434,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
error.obligation.predicate,
)
}
[errors @ .., last] => {
_ => {
format!(
"you could `clone` the value and consume it, if the \
following trait bounds could be satisfied: \
{} and `{}`",
errors
.iter()
.map(|e| format!("`{}`", e.obligation.predicate))
.collect::<Vec<_>>()
.join(", "),
last.obligation.predicate,
following trait bounds could be satisfied: {}",
listify(&errors, |e: &FulfillmentError<'tcx>| format!(
"`{}`",
e.obligation.predicate
))
.unwrap(),
)
}
};

View file

@ -596,19 +596,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.suggest_cloning(err, place_ty, expr, None);
}
let mut path = None;
let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path());
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty,
place: &place_desc,
span,
});
if let Some(path) = path {
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
path: path.display().to_string(),
});
}
} else {
binds_to.sort();
binds_to.dedup();
@ -635,19 +629,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.suggest_cloning(err, place_ty, expr, Some(use_spans));
}
let mut path = None;
let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path());
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty,
place: &place_desc,
span: use_span,
});
if let Some(path) = path {
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
path: path.display().to_string(),
});
}
use_spans.args_subdiag(err, |args_span| {
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
@ -845,19 +833,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.suggest_cloning(err, bind_to.ty, expr, None);
}
let mut path = None;
let ty = self.infcx.tcx.short_ty_string(bind_to.ty, &mut path);
let ty = self.infcx.tcx.short_string(bind_to.ty, err.long_ty_path());
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty,
place: place_desc,
span: binding_span,
});
if let Some(path) = path {
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
path: path.display().to_string(),
});
}
}
}

View file

@ -458,13 +458,6 @@ pub(crate) enum OnClosureNote<'a> {
},
}
#[derive(Subdiagnostic)]
#[note(borrowck_long_type_full_path)]
#[note(borrowck_long_type_consider_verbose)]
pub(crate) struct LongTypePath {
pub(crate) path: String,
}
#[derive(Subdiagnostic)]
pub(crate) enum TypeNoCopy<'a> {
#[label(borrowck_ty_no_impl_copy)]

View file

@ -56,7 +56,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) ->
let (ident, vdata, fields) = match substr.fields {
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
EnumMatching(_, v, fields) => (v.ident, &v.data, fields),
EnumMatching(v, fields) => (v.ident, &v.data, fields),
AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => {
cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")

View file

@ -1,215 +0,0 @@
//! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more.
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Expr, MetaItem, Mutability};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::{Ident, Span, Symbol, sym};
use thin_vec::{ThinVec, thin_vec};
use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::pathvec_std;
pub(crate) fn expand_deriving_rustc_decodable(
cx: &ExtCtxt<'_>,
span: Span,
mitem: &MetaItem,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
is_const: bool,
) {
let krate = sym::rustc_serialize;
let typaram = sym::__D;
let trait_def = TraitDef {
span,
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
skip_path_as_bound: false,
needs_copy_as_bound_if_packed: true,
additional_bounds: Vec::new(),
supports_unions: false,
methods: vec![MethodDef {
name: sym::decode,
generics: Bounds {
bounds: vec![(typaram, vec![Path::new_(
vec![krate, sym::Decoder],
vec![],
PathKind::Global,
)])],
},
explicit_self: false,
nonself_args: vec![(
Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut),
sym::d,
)],
ret_ty: Path(Path::new_(
pathvec_std!(result::Result),
vec![
Box::new(Self_),
Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
],
PathKind::Std,
)),
attributes: ast::AttrVec::new(),
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
decodable_substructure(a, b, c, krate)
})),
}],
associated_types: Vec::new(),
is_const,
};
trait_def.expand(cx, mitem, item, push)
}
fn decodable_substructure(
cx: &ExtCtxt<'_>,
trait_span: Span,
substr: &Substructure<'_>,
krate: Symbol,
) -> BlockOrExpr {
let decoder = substr.nonselflike_args[0].clone();
let recurse = vec![
Ident::new(krate, trait_span),
Ident::new(sym::Decodable, trait_span),
Ident::new(sym::decode, trait_span),
];
let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
// throw an underscore in front to suppress unused variable warnings
let blkarg = Ident::new(sym::_d, trait_span);
let blkdecoder = cx.expr_ident(trait_span, blkarg);
let expr = match substr.fields {
StaticStruct(_, summary) => {
let nfields = match summary {
Unnamed(fields, _) => fields.len(),
Named(fields) => fields.len(),
};
let fn_read_struct_field_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct_field]);
let path = cx.path_ident(trait_span, substr.type_ident);
let result =
decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| {
cx.expr_try(
span,
cx.expr_call_global(span, fn_read_struct_field_path.clone(), thin_vec![
blkdecoder.clone(),
cx.expr_str(span, name),
cx.expr_usize(span, field),
exprdecode.clone(),
]),
)
});
let result = cx.expr_ok(trait_span, result);
let fn_read_struct_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct]);
cx.expr_call_global(trait_span, fn_read_struct_path, thin_vec![
decoder,
cx.expr_str(trait_span, substr.type_ident.name),
cx.expr_usize(trait_span, nfields),
cx.lambda1(trait_span, result, blkarg),
])
}
StaticEnum(_, fields) => {
let variant = Ident::new(sym::i, trait_span);
let mut arms = ThinVec::with_capacity(fields.len() + 1);
let mut variants = ThinVec::with_capacity(fields.len());
let fn_read_enum_variant_arg_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant_arg]);
for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
variants.push(cx.expr_str(v_span, ident.name));
let path = cx.path(trait_span, vec![substr.type_ident, ident]);
let decoded =
decode_static_fields(cx, v_span, path, parts, |cx, span, _, field| {
let idx = cx.expr_usize(span, field);
cx.expr_try(
span,
cx.expr_call_global(
span,
fn_read_enum_variant_arg_path.clone(),
thin_vec![blkdecoder.clone(), idx, exprdecode.clone()],
),
)
});
arms.push(cx.arm(v_span, cx.pat_lit(v_span, cx.expr_usize(v_span, i)), decoded));
}
arms.push(cx.arm_unreachable(trait_span));
let result = cx.expr_ok(
trait_span,
cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms),
);
let lambda = cx.lambda(trait_span, vec![blkarg, variant], result);
let variant_array_ref = cx.expr_array_ref(trait_span, variants);
let fn_read_enum_variant_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]);
let result = cx.expr_call_global(trait_span, fn_read_enum_variant_path, thin_vec![
blkdecoder,
variant_array_ref,
lambda
]);
let fn_read_enum_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]);
cx.expr_call_global(trait_span, fn_read_enum_path, thin_vec![
decoder,
cx.expr_str(trait_span, substr.type_ident.name),
cx.lambda1(trait_span, result, blkarg),
])
}
_ => cx.dcx().bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
};
BlockOrExpr::new_expr(expr)
}
/// Creates a decoder for a single enum variant/struct:
/// - `outer_pat_path` is the path to this enum variant/struct
/// - `getarg` should retrieve the `usize`-th field with name `@str`.
fn decode_static_fields<F>(
cx: &ExtCtxt<'_>,
trait_span: Span,
outer_pat_path: ast::Path,
fields: &StaticFields,
mut getarg: F,
) -> P<Expr>
where
F: FnMut(&ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>,
{
match fields {
Unnamed(fields, is_tuple) => {
let path_expr = cx.expr_path(outer_pat_path);
if matches!(is_tuple, IsTuple::No) {
path_expr
} else {
let fields = fields
.iter()
.enumerate()
.map(|(i, &span)| getarg(cx, span, Symbol::intern(&format!("_field{i}")), i))
.collect();
cx.expr_call(trait_span, path_expr, fields)
}
}
Named(fields) => {
// use the field's span to get nicer error messages.
let fields = fields
.iter()
.enumerate()
.map(|(i, &(ident, span, _))| {
let arg = getarg(cx, span, ident.name, i);
cx.field_imm(span, ident, arg)
})
.collect();
cx.expr_struct(trait_span, outer_pat_path, fields)
}
}
}

View file

@ -42,7 +42,7 @@ pub(crate) fn expand_deriving_default(
StaticStruct(_, fields) => {
default_struct_substructure(cx, trait_span, substr, fields)
}
StaticEnum(enum_def, _) => {
StaticEnum(enum_def) => {
default_enum_substructure(cx, trait_span, enum_def, item.span())
}
_ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"),

View file

@ -1,284 +0,0 @@
//! The compiler code necessary to implement the `#[derive(RustcEncodable)]`
//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that
//! type-defining items may be tagged with
//! `#[derive(RustcEncodable, RustcDecodable)]`.
//!
//! For example, a type like:
//!
//! ```ignore (old code)
//! #[derive(RustcEncodable, RustcDecodable)]
//! struct Node { id: usize }
//! ```
//!
//! would generate two implementations like:
//!
//! ```ignore (old code)
//! # struct Node { id: usize }
//! impl<S: Encoder<E>, E> Encodable<S, E> for Node {
//! fn encode(&self, s: &mut S) -> Result<(), E> {
//! s.emit_struct("Node", 1, |this| {
//! this.emit_struct_field("id", 0, |this| {
//! Encodable::encode(&self.id, this)
//! /* this.emit_usize(self.id) can also be used */
//! })
//! })
//! }
//! }
//!
//! impl<D: Decoder<E>, E> Decodable<D, E> for Node {
//! fn decode(d: &mut D) -> Result<Node, E> {
//! d.read_struct("Node", 1, |this| {
//! match this.read_struct_field("id", 0, |this| Decodable::decode(this)) {
//! Ok(id) => Ok(Node { id: id }),
//! Err(e) => Err(e),
//! }
//! })
//! }
//! }
//! ```
//!
//! Other interesting scenarios are when the item has type parameters or
//! references other non-built-in types. A type definition like:
//!
//! ```ignore (old code)
//! # #[derive(RustcEncodable, RustcDecodable)]
//! # struct Span;
//! #[derive(RustcEncodable, RustcDecodable)]
//! struct Spanned<T> { node: T, span: Span }
//! ```
//!
//! would yield functions like:
//!
//! ```ignore (old code)
//! # #[derive(RustcEncodable, RustcDecodable)]
//! # struct Span;
//! # struct Spanned<T> { node: T, span: Span }
//! impl<
//! S: Encoder<E>,
//! E,
//! T: Encodable<S, E>
//! > Encodable<S, E> for Spanned<T> {
//! fn encode(&self, s: &mut S) -> Result<(), E> {
//! s.emit_struct("Spanned", 2, |this| {
//! this.emit_struct_field("node", 0, |this| self.node.encode(this))
//! .unwrap();
//! this.emit_struct_field("span", 1, |this| self.span.encode(this))
//! })
//! }
//! }
//!
//! impl<
//! D: Decoder<E>,
//! E,
//! T: Decodable<D, E>
//! > Decodable<D, E> for Spanned<T> {
//! fn decode(d: &mut D) -> Result<Spanned<T>, E> {
//! d.read_struct("Spanned", 2, |this| {
//! Ok(Spanned {
//! node: this.read_struct_field("node", 0, |this| Decodable::decode(this))
//! .unwrap(),
//! span: this.read_struct_field("span", 1, |this| Decodable::decode(this))
//! .unwrap(),
//! })
//! })
//! }
//! }
//! ```
use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::{Ident, Span, Symbol, sym};
use thin_vec::{ThinVec, thin_vec};
use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::pathvec_std;
pub(crate) fn expand_deriving_rustc_encodable(
cx: &ExtCtxt<'_>,
span: Span,
mitem: &MetaItem,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
is_const: bool,
) {
let krate = sym::rustc_serialize;
let typaram = sym::__S;
let trait_def = TraitDef {
span,
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
skip_path_as_bound: false,
needs_copy_as_bound_if_packed: true,
additional_bounds: Vec::new(),
supports_unions: false,
methods: vec![MethodDef {
name: sym::encode,
generics: Bounds {
bounds: vec![(typaram, vec![Path::new_(
vec![krate, sym::Encoder],
vec![],
PathKind::Global,
)])],
},
explicit_self: true,
nonself_args: vec![(
Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut),
sym::s,
)],
ret_ty: Path(Path::new_(
pathvec_std!(result::Result),
vec![
Box::new(Unit),
Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
],
PathKind::Std,
)),
attributes: AttrVec::new(),
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
encodable_substructure(a, b, c, krate)
})),
}],
associated_types: Vec::new(),
is_const,
};
trait_def.expand(cx, mitem, item, push)
}
fn encodable_substructure(
cx: &ExtCtxt<'_>,
trait_span: Span,
substr: &Substructure<'_>,
krate: Symbol,
) -> BlockOrExpr {
let encoder = substr.nonselflike_args[0].clone();
// throw an underscore in front to suppress unused variable warnings
let blkarg = Ident::new(sym::_e, trait_span);
let blkencoder = cx.expr_ident(trait_span, blkarg);
let fn_path = cx.expr_path(cx.path_global(trait_span, vec![
Ident::new(krate, trait_span),
Ident::new(sym::Encodable, trait_span),
Ident::new(sym::encode, trait_span),
]));
match substr.fields {
Struct(_, fields) => {
let fn_emit_struct_field_path =
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]);
let mut stmts = ThinVec::new();
for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() {
let name = match name {
Some(id) => id.name,
None => Symbol::intern(&format!("_field{i}")),
};
let self_ref = cx.expr_addr_of(span, self_expr.clone());
let enc =
cx.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]);
let lambda = cx.lambda1(span, enc, blkarg);
let call = cx.expr_call_global(span, fn_emit_struct_field_path.clone(), thin_vec![
blkencoder.clone(),
cx.expr_str(span, name),
cx.expr_usize(span, i),
lambda,
]);
// last call doesn't need a try!
let last = fields.len() - 1;
let call = if i != last {
cx.expr_try(span, call)
} else {
cx.expr(span, ExprKind::Ret(Some(call)))
};
let stmt = cx.stmt_expr(call);
stmts.push(stmt);
}
// unit structs have no fields and need to return Ok()
let blk = if stmts.is_empty() {
let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new()));
cx.lambda1(trait_span, ok, blkarg)
} else {
cx.lambda_stmts_1(trait_span, stmts, blkarg)
};
let fn_emit_struct_path =
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]);
let expr = cx.expr_call_global(trait_span, fn_emit_struct_path, thin_vec![
encoder,
cx.expr_str(trait_span, substr.type_ident.name),
cx.expr_usize(trait_span, fields.len()),
blk,
]);
BlockOrExpr::new_expr(expr)
}
EnumMatching(idx, variant, fields) => {
// We're not generating an AST that the borrow checker is expecting,
// so we need to generate a unique local variable to take the
// mutable loan out on, otherwise we get conflicts which don't
// actually exist.
let me = cx.stmt_let(trait_span, false, blkarg, encoder);
let encoder = cx.expr_ident(trait_span, blkarg);
let fn_emit_enum_variant_arg_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]);
let mut stmts = ThinVec::new();
if !fields.is_empty() {
let last = fields.len() - 1;
for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() {
let self_ref = cx.expr_addr_of(span, self_expr.clone());
let enc = cx
.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]);
let lambda = cx.lambda1(span, enc, blkarg);
let call = cx.expr_call_global(
span,
fn_emit_enum_variant_arg_path.clone(),
thin_vec![blkencoder.clone(), cx.expr_usize(span, i), lambda],
);
let call = if i != last {
cx.expr_try(span, call)
} else {
cx.expr(span, ExprKind::Ret(Some(call)))
};
stmts.push(cx.stmt_expr(call));
}
} else {
let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new()));
let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok)));
stmts.push(cx.stmt_expr(ret_ok));
}
let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
let name = cx.expr_str(trait_span, variant.ident.name);
let fn_emit_enum_variant_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]);
let call = cx.expr_call_global(trait_span, fn_emit_enum_variant_path, thin_vec![
blkencoder,
name,
cx.expr_usize(trait_span, *idx),
cx.expr_usize(trait_span, fields.len()),
blk,
]);
let blk = cx.lambda1(trait_span, call, blkarg);
let fn_emit_enum_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]);
let expr = cx.expr_call_global(trait_span, fn_emit_enum_path, thin_vec![
encoder,
cx.expr_str(trait_span, substr.type_ident.name),
blk
]);
BlockOrExpr::new_mixed(thin_vec![me], Some(expr))
}
_ => cx.dcx().bug("expected Struct or EnumMatching in derive(Encodable)"),
}
}

View file

@ -311,7 +311,7 @@ pub(crate) enum SubstructureFields<'a> {
/// Matching variants of the enum: variant index, ast::Variant,
/// fields: the field name is only non-`None` in the case of a struct
/// variant.
EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>),
EnumMatching(&'a ast::Variant, Vec<FieldInfo>),
/// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as
/// if they were fields. The second field is the expression to combine the
@ -322,7 +322,7 @@ pub(crate) enum SubstructureFields<'a> {
StaticStruct(&'a ast::VariantData, StaticFields),
/// A static method where `Self` is an enum.
StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
StaticEnum(&'a ast::EnumDef),
}
/// Combine the values of all the fields together. The last argument is
@ -1270,7 +1270,7 @@ impl<'a> MethodDef<'a> {
trait_,
type_ident,
nonselflike_args,
&EnumMatching(0, variant, Vec::new()),
&EnumMatching(variant, Vec::new()),
);
}
}
@ -1282,9 +1282,8 @@ impl<'a> MethodDef<'a> {
// where each tuple has length = selflike_args.len()
let mut match_arms: ThinVec<ast::Arm> = variants
.iter()
.enumerate()
.filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty()))
.map(|(index, variant)| {
.filter(|&v| !(unify_fieldless_variants && v.data.fields().is_empty()))
.map(|variant| {
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
// (see "Final wrinkle" note below for why.)
@ -1316,7 +1315,7 @@ impl<'a> MethodDef<'a> {
// expressions for referencing every field of every
// Self arg, assuming all are instances of VariantK.
// Build up code associated with such a case.
let substructure = EnumMatching(index, variant, fields);
let substructure = EnumMatching(variant, fields);
let arm_expr = self
.call_substructure_method(
cx,
@ -1344,7 +1343,7 @@ impl<'a> MethodDef<'a> {
trait_,
type_ident,
nonselflike_args,
&EnumMatching(0, v, Vec::new()),
&EnumMatching(v, Vec::new()),
)
.into_expr(cx, span),
)
@ -1407,21 +1406,12 @@ impl<'a> MethodDef<'a> {
type_ident: Ident,
nonselflike_args: &[P<Expr>],
) -> BlockOrExpr {
let summary = enum_def
.variants
.iter()
.map(|v| {
let sp = v.span.with_ctxt(trait_.span.ctxt());
let summary = trait_.summarise_struct(cx, &v.data);
(v.ident, sp, summary)
})
.collect();
self.call_substructure_method(
cx,
trait_,
type_ident,
nonselflike_args,
&StaticEnum(enum_def, summary),
&StaticEnum(enum_def),
)
}
}

View file

@ -21,7 +21,6 @@ pub(crate) struct Path {
#[derive(Clone)]
pub(crate) enum PathKind {
Local,
Global,
Std,
}
@ -57,7 +56,6 @@ impl Path {
let params = tys.map(GenericArg::Type).collect();
match self.kind {
PathKind::Global => cx.path_all(span, true, idents, params),
PathKind::Local => cx.path_all(span, false, idents, params),
PathKind::Std => {
let def_site = cx.with_def_site_ctxt(DUMMY_SP);

View file

@ -23,9 +23,7 @@ pub(crate) mod bounds;
pub(crate) mod clone;
pub(crate) mod coerce_pointee;
pub(crate) mod debug;
pub(crate) mod decodable;
pub(crate) mod default;
pub(crate) mod encodable;
pub(crate) mod hash;
#[path = "cmp/eq.rs"]

View file

@ -8,7 +8,9 @@ use rustc_ast::{
token,
};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
use rustc_errors::{
Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize,
};
use rustc_expand::base::*;
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
@ -975,15 +977,11 @@ fn report_invalid_references(
} else {
MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect())
};
let arg_list = if let &[index] = &indexes[..] {
format!("argument {index}")
} else {
let tail = indexes.pop().unwrap();
format!(
"arguments {head} and {tail}",
head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
)
};
let arg_list = format!(
"argument{} {}",
pluralize!(indexes.len()),
listify(&indexes, |i: &usize| i.to_string()).unwrap_or_default()
);
e = ecx.dcx().struct_span_err(
span,
format!("invalid reference to positional {arg_list} ({num_args_desc})"),

View file

@ -132,8 +132,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
Ord: ord::expand_deriving_ord,
PartialEq: partial_eq::expand_deriving_partial_eq,
PartialOrd: partial_ord::expand_deriving_partial_ord,
RustcDecodable: decodable::expand_deriving_rustc_decodable,
RustcEncodable: encodable::expand_deriving_rustc_encodable,
CoercePointee: coerce_pointee::expand_deriving_coerce_pointee,
}

View file

@ -692,7 +692,7 @@ pub(crate) fn run_aot(
if tcx.dep_graph.is_fully_enabled() {
for cgu in cgus {
tcx.ensure().codegen_unit(cgu.name());
tcx.ensure_ok().codegen_unit(cgu.name());
}
}

View file

@ -420,8 +420,14 @@ impl<'ll> CodegenCx<'ll, '_> {
let g = if val_llty == llty {
g
} else {
// If we created the global with the wrong type,
// correct the type.
// codegen_static_initializer creates the global value just from the
// `Allocation` data by generating one big struct value that is just
// all the bytes and pointers after each other. This will almost never
// match the type that the static was declared with. Unfortunately
// we can't just LLVMConstBitCast our way out of it because that has very
// specific rules on what can be cast. So instead of adding a new way to
// generate static initializers that match the static's type, we picked
// the easier option and retroactively change the type of the static item itself.
let name = llvm::get_value_name(g).to_vec();
llvm::set_value_name(g, b"");

View file

@ -634,7 +634,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// unnecessarily.
if tcx.dep_graph.is_fully_enabled() {
for cgu in codegen_units {
tcx.ensure().codegen_unit(cgu.name());
tcx.ensure_ok().codegen_unit(cgu.name());
}
}

View file

@ -1240,6 +1240,17 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
self.visit_field(val, 0, &self.ecx.project_index(val, 0)?)?;
}
}
ty::Pat(base, pat) => {
// First check that the base type is valid
self.visit_value(&val.transmute(self.ecx.layout_of(*base)?, self.ecx)?)?;
// When you extend this match, make sure to also add tests to
// tests/ui/type/pattern_types/validity.rs((
match **pat {
// Range patterns are precisely reflected into `valid_range` and thus
// handled fully by `visit_scalar` (called below).
ty::PatternKind::Range { .. } => {},
}
}
_ => {
// default handler
try_validation!(

View file

@ -1,7 +1,6 @@
use std::{env, error, fmt, fs, io};
use rustc_session::EarlyDiagCtxt;
use rustc_span::ErrorGuaranteed;
/// Expands argfiles in command line arguments.
#[derive(Default)]
@ -118,22 +117,22 @@ pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<Stri
///
/// This function is identical to [`env::args()`] except that it emits an error when it encounters
/// non-Unicode arguments instead of panicking.
pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Result<Vec<String>, ErrorGuaranteed> {
let mut res = Ok(Vec::new());
pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Vec<String> {
let mut args = Vec::new();
let mut guar = Ok(());
for (i, arg) in env::args_os().enumerate() {
match arg.into_string() {
Ok(arg) => {
if let Ok(args) = &mut res {
args.push(arg);
}
}
Ok(arg) => args.push(arg),
Err(arg) => {
res =
guar =
Err(early_dcx.early_err(format!("argument {i} is not valid Unicode: {arg:?}")))
}
}
}
res
if let Err(guar) = guar {
guar.raise_fatal();
}
args
}
#[derive(Debug)]

View file

@ -317,7 +317,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
if let Some(pp_mode) = sess.opts.pretty {
if pp_mode.needs_ast_map() {
create_and_enter_global_ctxt(compiler, krate, |tcx| {
tcx.ensure().early_lint_checks(());
tcx.ensure_ok().early_lint_checks(());
pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx });
passes::write_dep_info(tcx);
});
@ -365,7 +365,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
return early_exit();
}
tcx.ensure().analysis(());
tcx.ensure_ok().analysis(());
if callbacks.after_analysis(compiler, tcx) == Compilation::Stop {
return early_exit();
@ -1212,9 +1212,9 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, FatalError> {
/// Variant of `catch_fatal_errors` for the `interface::Result` return type
/// that also computes the exit code.
pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
pub fn catch_with_exit_code(f: impl FnOnce()) -> i32 {
match catch_fatal_errors(f) {
Ok(Ok(())) => EXIT_SUCCESS,
Ok(()) => EXIT_SUCCESS,
_ => EXIT_FAILURE,
}
}
@ -1499,10 +1499,8 @@ pub fn main() -> ! {
install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
install_ctrlc_handler();
let exit_code = catch_with_exit_code(|| {
run_compiler(&args::raw_args(&early_dcx)?, &mut callbacks);
Ok(())
});
let exit_code =
catch_with_exit_code(|| run_compiler(&args::raw_args(&early_dcx), &mut callbacks));
if let Some(format) = callbacks.time_passes {
let end_rss = get_resident_set_size();

View file

@ -222,7 +222,7 @@ impl<'tcx> PrintExtra<'tcx> {
pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
if ppm.needs_analysis() {
ex.tcx().ensure().analysis(());
ex.tcx().ensure_ok().analysis(());
}
let (src, src_name) = get_source(sess);

View file

@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::panic;
use std::path::PathBuf;
use std::thread::panicking;
use rustc_data_structures::fx::FxIndexMap;
@ -301,6 +302,7 @@ pub struct DiagInner {
pub is_lint: Option<IsLint>,
pub long_ty_path: Option<PathBuf>,
/// With `-Ztrack_diagnostics` enabled,
/// we print where in rustc this error was emitted.
pub(crate) emitted_at: DiagLocation,
@ -324,6 +326,7 @@ impl DiagInner {
args: Default::default(),
sort_span: DUMMY_SP,
is_lint: None,
long_ty_path: None,
emitted_at: DiagLocation::caller(),
}
}
@ -641,7 +644,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
found_label: &dyn fmt::Display,
found: DiagStyledString,
) -> &mut Self {
self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
self.note_expected_found_extra(
expected_label,
expected,
found_label,
found,
DiagStyledString::normal(""),
DiagStyledString::normal(""),
)
}
#[rustc_lint_diagnostics]
@ -651,8 +661,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
expected: DiagStyledString,
found_label: &dyn fmt::Display,
found: DiagStyledString,
expected_extra: &dyn fmt::Display,
found_extra: &dyn fmt::Display,
expected_extra: DiagStyledString,
found_extra: DiagStyledString,
) -> &mut Self {
let expected_label = expected_label.to_string();
let expected_label = if expected_label.is_empty() {
@ -677,10 +687,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
expected_label
))];
msg.extend(expected.0);
msg.push(StringPart::normal(format!("`{expected_extra}\n")));
msg.push(StringPart::normal(format!("`")));
msg.extend(expected_extra.0);
msg.push(StringPart::normal(format!("\n")));
msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
msg.extend(found.0);
msg.push(StringPart::normal(format!("`{found_extra}")));
msg.push(StringPart::normal(format!("`")));
msg.extend(found_extra.0);
// For now, just attach these as notes.
self.highlighted_note(msg);
@ -1293,9 +1306,37 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// `cancel`, etc. Afterwards, `drop` is the only code that will be run on
/// `self`.
fn take_diag(&mut self) -> DiagInner {
if let Some(path) = &self.long_ty_path {
self.note(format!(
"the full name for the type has been written to '{}'",
path.display()
));
self.note("consider using `--verbose` to print the full type name to the console");
}
Box::into_inner(self.diag.take().unwrap())
}
/// This method allows us to access the path of the file where "long types" are written to.
///
/// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set,
/// and if it has been then we add a note mentioning the file where the "long types" were
/// written to.
///
/// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing
/// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that
/// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the
/// user where we wrote the file to is only printed once at most, *and* it makes it much harder
/// to forget to set it.
///
/// If the diagnostic hasn't been created before a "short ty string" is created, then you should
/// ensure that this method is called to set it `*diag.long_ty_path() = path`.
///
/// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a
/// scope, `diag.long_ty_path()` should be called once somewhere close by.
pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
&mut self.long_ty_path
}
/// Most `emit_producing_guarantee` functions use this as a starting point.
fn emit_producing_nothing(mut self) {
let diag = self.take_diag();

View file

@ -35,8 +35,8 @@ use crate::snippet::{
use crate::styled_buffer::StyledBuffer;
use crate::translation::{Translate, to_fluent_args};
use crate::{
CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle,
Level, MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl,
CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level,
MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl,
};
/// Default column width, used in tests and when terminal dimensions cannot be determined.
@ -537,11 +537,10 @@ impl Emitter for HumanEmitter {
}
/// An emitter that does nothing when emitting a non-fatal diagnostic.
/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent
/// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent
/// failures of rustc, as witnessed e.g. in issue #89358.
pub struct SilentEmitter {
pub fallback_bundle: LazyFallbackBundle,
pub fatal_dcx: DiagCtxt,
pub fatal_emitter: Box<dyn Emitter + DynSend>,
pub fatal_note: Option<String>,
pub emit_fatal_diagnostic: bool,
}
@ -552,9 +551,7 @@ impl Translate for SilentEmitter {
}
fn fallback_fluent_bundle(&self) -> &FluentBundle {
// Ideally this field wouldn't be necessary and the fallback bundle in `fatal_dcx` would be
// used but the lock prevents this.
&self.fallback_bundle
self.fatal_emitter.fallback_fluent_bundle()
}
}
@ -563,12 +560,12 @@ impl Emitter for SilentEmitter {
None
}
fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) {
fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) {
if self.emit_fatal_diagnostic && diag.level == Level::Fatal {
if let Some(fatal_note) = &self.fatal_note {
diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
}
self.fatal_dcx.handle().emit_diagnostic(diag);
self.fatal_emitter.emit_diagnostic(diag, registry);
}
}
}

View file

@ -59,13 +59,13 @@ use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
use rustc_data_structures::AtomicRef;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
use rustc_data_structures::sync::Lock;
use rustc_data_structures::sync::{DynSend, Lock};
pub use rustc_error_messages::{
DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
};
use rustc_lint_defs::LintExpectationId;
pub use rustc_lint_defs::{Applicability, pluralize};
pub use rustc_lint_defs::{Applicability, listify, pluralize};
use rustc_macros::{Decodable, Encodable};
pub use rustc_span::ErrorGuaranteed;
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
@ -676,57 +676,44 @@ impl DiagCtxt {
Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
}
pub fn make_silent(
&self,
fallback_bundle: LazyFallbackBundle,
fatal_note: Option<String>,
emit_fatal_diagnostic: bool,
) {
self.wrap_emitter(|old_dcx| {
Box::new(emitter::SilentEmitter {
fallback_bundle,
fatal_dcx: DiagCtxt { inner: Lock::new(old_dcx) },
fatal_note,
emit_fatal_diagnostic,
})
});
}
fn wrap_emitter<F>(&self, f: F)
where
F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>,
{
// A empty type that implements `Emitter` so that a `DiagCtxtInner` can be constructed
// to temporarily swap in place of the real one, which will be used in constructing
// its replacement.
pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) {
// An empty type that implements `Emitter` to temporarily swap in place of the real one,
// which will be used in constructing its replacement.
struct FalseEmitter;
impl Emitter for FalseEmitter {
fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) {
unimplemented!("false emitter must only used during `wrap_emitter`")
unimplemented!("false emitter must only used during `make_silent`")
}
fn source_map(&self) -> Option<&SourceMap> {
unimplemented!("false emitter must only used during `wrap_emitter`")
unimplemented!("false emitter must only used during `make_silent`")
}
}
impl translation::Translate for FalseEmitter {
fn fluent_bundle(&self) -> Option<&FluentBundle> {
unimplemented!("false emitter must only used during `wrap_emitter`")
unimplemented!("false emitter must only used during `make_silent`")
}
fn fallback_fluent_bundle(&self) -> &FluentBundle {
unimplemented!("false emitter must only used during `wrap_emitter`")
unimplemented!("false emitter must only used during `make_silent`")
}
}
let mut inner = self.inner.borrow_mut();
let mut prev_dcx = DiagCtxtInner::new(Box::new(FalseEmitter));
std::mem::swap(&mut *inner, &mut prev_dcx);
let new_emitter = f(prev_dcx);
let mut new_dcx = DiagCtxtInner::new(new_emitter);
std::mem::swap(&mut *inner, &mut new_dcx);
let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>;
std::mem::swap(&mut inner.emitter, &mut prev_emitter);
let new_emitter = Box::new(emitter::SilentEmitter {
fatal_emitter: prev_emitter,
fatal_note,
emit_fatal_diagnostic,
});
inner.emitter = new_emitter;
}
pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
self.inner.borrow_mut().emitter = emitter;
}
/// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
@ -1999,18 +1986,6 @@ pub fn a_or_an(s: &str) -> &'static str {
}
}
/// Grammatical tool for displaying messages to end users in a nice form.
///
/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
match v {
[] => "".to_string(),
[a] => a.to_string(),
[a, b] => format!("{a} and {b}"),
[a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)),
}
}
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum TerminalUrl {
No,

View file

@ -616,7 +616,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
),
rustc_attr!(
rustc_allowed_through_unstable_modules, Normal, template!(Word, NameValueStr: "deprecation message"),
rustc_allowed_through_unstable_modules, Normal, template!(NameValueStr: "deprecation message"),
WarnFollowing, EncodeCrossCrate::No,
"rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
through unstable paths"

View file

@ -234,6 +234,9 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a
.help = consider moving this inherent impl into the crate defining the type if possible
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
hir_analysis_invalid_base_type = `{$ty}` is not a valid base type for range patterns
.note = range patterns only support integers
hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}`
.note = type of `self` must not be a method generic parameter type
@ -438,7 +441,6 @@ hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pat
.label = this type is the same as the inner type without a pattern
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
.label = not allowed in type signatures
hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
.label = `Self` is not a generic argument, but an alias to the type of the {$what}

View file

@ -778,13 +778,13 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
match tcx.def_kind(def_id) {
DefKind::Static { .. } => {
tcx.ensure().typeck(def_id);
tcx.ensure_ok().typeck(def_id);
maybe_check_static_with_link_section(tcx, def_id);
check_static_inhabited(tcx, def_id);
check_static_linkage(tcx, def_id);
}
DefKind::Const => {
tcx.ensure().typeck(def_id);
tcx.ensure_ok().typeck(def_id);
}
DefKind::Enum => {
check_enum(tcx, def_id);
@ -804,7 +804,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
DefKind::Impl { of_trait } => {
if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) {
if tcx
.ensure()
.ensure_ok()
.coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id)
.is_ok()
{
@ -1042,7 +1042,7 @@ fn check_impl_items_against_trait<'tcx>(
continue;
};
let res = tcx.ensure().compare_impl_item(impl_item.expect_local());
let res = tcx.ensure_ok().compare_impl_item(impl_item.expect_local());
if res.is_ok() {
match ty_impl_item.kind {
@ -1488,7 +1488,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
for v in def.variants() {
if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
tcx.ensure().typeck(discr_def_id.expect_local());
tcx.ensure_ok().typeck(discr_def_id.expect_local());
}
}

View file

@ -2034,7 +2034,7 @@ pub(super) fn check_type_bounds<'tcx>(
) -> Result<(), ErrorGuaranteed> {
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
tcx.ensure().coherent_trait(impl_trait_ref.def_id)?;
tcx.ensure_ok().coherent_trait(impl_trait_ref.def_id)?;
let param_env = tcx.param_env(impl_ty.def_id);
debug!(?param_env);

View file

@ -1046,7 +1046,7 @@ fn check_associated_item(
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
tcx.ensure()
tcx.ensure_ok()
.coherent_trait(tcx.parent(item.trait_item_def_id.unwrap_or(item_id.into())))?;
let self_ty = match item.container {
@ -1354,7 +1354,7 @@ fn check_impl<'tcx>(
let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().instantiate_identity();
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
tcx.ensure().coherent_trait(trait_ref.def_id)?;
tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
let trait_span = hir_trait_ref.path.span;
let trait_ref = wfcx.normalize(
trait_span,
@ -2268,11 +2268,13 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
let items = tcx.hir_module_items(module);
let res = items
.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))
.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)))
.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)))
.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)))
.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item)));
.par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))
.and(items.par_impl_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
.and(items.par_trait_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
.and(
items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)),
)
.and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item)));
if module == LocalModDefId::CRATE_DEF_ID {
super::entry::check_for_entry_fn(tcx);
}

View file

@ -192,7 +192,7 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E
// errors; other parts of the code may demand it for the info of
// course.
let span = tcx.def_span(impl_did);
tcx.at(span).ensure().coerce_unsized_info(impl_did)
tcx.at(span).ensure_ok().coerce_unsized_info(impl_did)
}
fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {

View file

@ -151,7 +151,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
let Some(impls) = tcx.all_local_trait_impls(()).get(&def_id) else { return Ok(()) };
// Trigger building the specialization graph for the trait. This will detect and report any
// overlap errors.
let mut res = tcx.ensure().specialization_graph_of(def_id);
let mut res = tcx.ensure_ok().specialization_graph_of(def_id);
for &impl_def_id in impls {
let trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
@ -162,7 +162,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
.and(check_impl(tcx, impl_def_id, trait_ref, trait_def))
.and(check_object_overlap(tcx, impl_def_id, trait_ref))
.and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def))
.and(tcx.ensure().orphan_check_impl(impl_def_id))
.and(tcx.ensure_ok().orphan_check_impl(impl_def_id))
.and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header));
}

View file

@ -292,16 +292,16 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
match param.kind {
hir::GenericParamKind::Lifetime { .. } => {}
hir::GenericParamKind::Type { default: Some(_), .. } => {
self.tcx.ensure().type_of(param.def_id);
self.tcx.ensure_ok().type_of(param.def_id);
}
hir::GenericParamKind::Type { .. } => {}
hir::GenericParamKind::Const { default, .. } => {
self.tcx.ensure().type_of(param.def_id);
self.tcx.ensure_ok().type_of(param.def_id);
if let Some(default) = default {
// need to store default and type of default
self.tcx.ensure().const_param_default(param.def_id);
self.tcx.ensure_ok().const_param_default(param.def_id);
if let hir::ConstArgKind::Anon(ac) = default.kind {
self.tcx.ensure().type_of(ac.def_id);
self.tcx.ensure_ok().type_of(ac.def_id);
}
}
}
@ -312,8 +312,8 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Closure(closure) = expr.kind {
self.tcx.ensure().generics_of(closure.def_id);
self.tcx.ensure().codegen_fn_attrs(closure.def_id);
self.tcx.ensure_ok().generics_of(closure.def_id);
self.tcx.ensure_ok().codegen_fn_attrs(closure.def_id);
// We do not call `type_of` for closures here as that
// depends on typecheck and would therefore hide
// any further errors in case one typeck fails.
@ -325,15 +325,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
/// `check_item_type` ensures that it's called instead.
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) {
let def_id = opaque.def_id;
self.tcx.ensure().generics_of(def_id);
self.tcx.ensure().predicates_of(def_id);
self.tcx.ensure().explicit_item_bounds(def_id);
self.tcx.ensure().explicit_item_self_bounds(def_id);
self.tcx.ensure().item_bounds(def_id);
self.tcx.ensure().item_self_bounds(def_id);
self.tcx.ensure_ok().generics_of(def_id);
self.tcx.ensure_ok().predicates_of(def_id);
self.tcx.ensure_ok().explicit_item_bounds(def_id);
self.tcx.ensure_ok().explicit_item_self_bounds(def_id);
self.tcx.ensure_ok().item_bounds(def_id);
self.tcx.ensure_ok().item_self_bounds(def_id);
if self.tcx.is_conditionally_const(def_id) {
self.tcx.ensure().explicit_implied_const_bounds(def_id);
self.tcx.ensure().const_conditions(def_id);
self.tcx.ensure_ok().explicit_implied_const_bounds(def_id);
self.tcx.ensure_ok().const_conditions(def_id);
}
intravisit::walk_opaque_ty(self, opaque);
}
@ -683,20 +683,20 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
hir::ItemKind::ForeignMod { items, .. } => {
for item in *items {
let item = tcx.hir().foreign_item(item.id);
tcx.ensure().generics_of(item.owner_id);
tcx.ensure().type_of(item.owner_id);
tcx.ensure().predicates_of(item.owner_id);
tcx.ensure_ok().generics_of(item.owner_id);
tcx.ensure_ok().type_of(item.owner_id);
tcx.ensure_ok().predicates_of(item.owner_id);
if tcx.is_conditionally_const(def_id) {
tcx.ensure().explicit_implied_const_bounds(def_id);
tcx.ensure().const_conditions(def_id);
tcx.ensure_ok().explicit_implied_const_bounds(def_id);
tcx.ensure_ok().const_conditions(def_id);
}
match item.kind {
hir::ForeignItemKind::Fn(..) => {
tcx.ensure().codegen_fn_attrs(item.owner_id);
tcx.ensure().fn_sig(item.owner_id)
tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
tcx.ensure_ok().fn_sig(item.owner_id)
}
hir::ForeignItemKind::Static(..) => {
tcx.ensure().codegen_fn_attrs(item.owner_id);
tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_foreign_item(item);
placeholder_type_error(
@ -713,40 +713,40 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
}
}
hir::ItemKind::Enum(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
lower_enum_variant_types(tcx, def_id.to_def_id());
}
hir::ItemKind::Impl { .. } => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().impl_trait_header(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure().associated_items(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().impl_trait_header(def_id);
tcx.ensure_ok().predicates_of(def_id);
tcx.ensure_ok().associated_items(def_id);
}
hir::ItemKind::Trait(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().trait_def(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().trait_def(def_id);
tcx.at(it.span).explicit_super_predicates_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure().associated_items(def_id);
tcx.ensure_ok().predicates_of(def_id);
tcx.ensure_ok().associated_items(def_id);
}
hir::ItemKind::TraitAlias(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.at(it.span).explicit_implied_predicates_of(def_id);
tcx.at(it.span).explicit_super_predicates_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
}
hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
for f in struct_def.fields() {
tcx.ensure().generics_of(f.def_id);
tcx.ensure().type_of(f.def_id);
tcx.ensure().predicates_of(f.def_id);
tcx.ensure_ok().generics_of(f.def_id);
tcx.ensure_ok().type_of(f.def_id);
tcx.ensure_ok().predicates_of(f.def_id);
}
if let Some(ctor_def_id) = struct_def.ctor_def_id() {
@ -755,15 +755,15 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
}
hir::ItemKind::TyAlias(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
}
hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
if !ty.is_suggestable_infer_ty() {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_item(it);
@ -779,11 +779,11 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
}
hir::ItemKind::Fn { .. } => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure().fn_sig(def_id);
tcx.ensure().codegen_fn_attrs(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
tcx.ensure_ok().fn_sig(def_id);
tcx.ensure_ok().codegen_fn_attrs(def_id);
}
}
}
@ -791,18 +791,18 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
let trait_item = tcx.hir().trait_item(trait_item_id);
let def_id = trait_item_id.owner_id;
tcx.ensure().generics_of(def_id);
tcx.ensure_ok().generics_of(def_id);
let icx = ItemCtxt::new(tcx, def_id.def_id);
match trait_item.kind {
hir::TraitItemKind::Fn(..) => {
tcx.ensure().codegen_fn_attrs(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().fn_sig(def_id);
tcx.ensure_ok().codegen_fn_attrs(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().fn_sig(def_id);
}
hir::TraitItemKind::Const(ty, body_id) => {
tcx.ensure().type_of(def_id);
tcx.ensure_ok().type_of(def_id);
if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
&& !(ty.is_suggestable_infer_ty() && body_id.is_some())
{
@ -821,9 +821,9 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
}
hir::TraitItemKind::Type(_, Some(_)) => {
tcx.ensure().item_bounds(def_id);
tcx.ensure().item_self_bounds(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure_ok().item_bounds(def_id);
tcx.ensure_ok().item_self_bounds(def_id);
tcx.ensure_ok().type_of(def_id);
// Account for `type T = _;`.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
@ -838,8 +838,8 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
}
hir::TraitItemKind::Type(_, None) => {
tcx.ensure().item_bounds(def_id);
tcx.ensure().item_self_bounds(def_id);
tcx.ensure_ok().item_bounds(def_id);
tcx.ensure_ok().item_self_bounds(def_id);
// #74612: Visit and try to find bad placeholders
// even if there is no concrete type.
let mut visitor = HirPlaceholderCollector::default();
@ -856,20 +856,20 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
}
};
tcx.ensure().predicates_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
}
fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
let def_id = impl_item_id.owner_id;
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
let impl_item = tcx.hir().impl_item(impl_item_id);
let icx = ItemCtxt::new(tcx, def_id.def_id);
match impl_item.kind {
hir::ImplItemKind::Fn(..) => {
tcx.ensure().codegen_fn_attrs(def_id);
tcx.ensure().fn_sig(def_id);
tcx.ensure_ok().codegen_fn_attrs(def_id);
tcx.ensure_ok().fn_sig(def_id);
}
hir::ImplItemKind::Type(_) => {
// Account for `type T = _;`
@ -904,9 +904,9 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
}
fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
}
fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
@ -937,9 +937,9 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
);
for f in &variant.fields {
tcx.ensure().generics_of(f.did);
tcx.ensure().type_of(f.did);
tcx.ensure().predicates_of(f.did);
tcx.ensure_ok().generics_of(f.did);
tcx.ensure_ok().type_of(f.did);
tcx.ensure_ok().predicates_of(f.did);
}
// Lower the ctor, if any. This also registers the variant as an item.

View file

@ -1,4 +1,5 @@
use rustc_macros::Diagnostic;
use rustc_middle::ty::Ty;
use rustc_span::Span;
#[derive(Diagnostic)]
@ -7,3 +8,14 @@ pub(crate) struct WildPatTy {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_invalid_base_type)]
pub(crate) struct InvalidBaseType<'tcx> {
pub ty: Ty<'tcx>,
#[primary_span]
pub ty_span: Span,
pub pat: &'static str,
#[note]
pub pat_span: Span,
}

View file

@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::unord::UnordMap;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err,
Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@ -808,14 +808,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|(trait_, mut assocs)| {
assocs.sort();
let trait_ = trait_.print_trait_sugared();
format!("{} in `{trait_}`", match &assocs[..] {
[] => String::new(),
[only] => format!("`{only}`"),
[assocs @ .., last] => format!(
"{} and `{last}`",
assocs.iter().map(|a| format!("`{a}`")).collect::<Vec<_>>().join(", ")
),
})
format!(
"{} in `{trait_}`",
listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
)
})
.collect::<Vec<String>>();
names.sort();
@ -1075,18 +1071,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
})
.collect();
let this_type = match &types_and_spans[..] {
[.., _, (last, _)] => format!(
"{} and {last}",
types_and_spans[..types_and_spans.len() - 1]
.iter()
.map(|(x, _)| x.as_str())
.intersperse(", ")
.collect::<String>()
),
[(only, _)] => only.to_string(),
[] => bug!("expected one segment to deny"),
};
let this_type = listify(&types_and_spans, |(t, _)| t.to_string())
.expect("expected one segment to deny");
let arg_spans: Vec<Span> = segments
.clone()
@ -1102,21 +1088,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ProhibitGenericsArg::Infer => kinds.push("generic"),
});
let (kind, s) = match kinds[..] {
[.., _, last] => (
format!(
"{} and {last}",
kinds[..kinds.len() - 1]
.iter()
.map(|&x| x)
.intersperse(", ")
.collect::<String>()
),
"s",
),
[only] => (only.to_string(), ""),
[] => bug!("expected at least one generic to prohibit"),
};
let s = pluralize!(kinds.len());
let kind =
listify(&kinds, |k| k.to_string()).expect("expected at least one generic to prohibit");
let last_span = *arg_spans.last().unwrap();
let span: MultiSpan = arg_spans.into();
let mut err = struct_span_code_err!(

View file

@ -53,7 +53,7 @@ use tracing::{debug, instrument};
use crate::bounds::Bounds;
use crate::check::check_abi_fn_ptr;
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy};
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, WildPatTy};
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
use crate::middle::resolve_bound_vars as rbv;
@ -2432,6 +2432,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.ty_infer(None, hir_ty.span)
}
hir::TyKind::Pat(ty, pat) => {
let ty_span = ty.span;
let ty = self.lower_ty(ty);
let pat_ty = match pat.kind {
hir::PatKind::Wild => {
@ -2439,6 +2440,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Ty::new_error(tcx, err)
}
hir::PatKind::Range(start, end, include_end) => {
let ty = match ty.kind() {
ty::Int(_) | ty::Uint(_) | ty::Char => ty,
_ => Ty::new_error(
tcx,
self.dcx().emit_err(InvalidBaseType {
ty,
pat: "range",
ty_span,
pat_span: pat.span,
}),
),
};
let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
let (c, c_ty) = match expr.kind {
hir::PatExprKind::Lit { lit, negated } => {

View file

@ -62,7 +62,7 @@ pub(crate) fn check_impl_wf(
// Check that the args are constrained. We queryfied the check for ty/const params
// since unconstrained type/const params cause ICEs in projection, so we want to
// detect those specifically and project those to `TyKind::Error`.
let mut res = tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
let mut res = tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id));
if tcx.features().min_specialization() {

View file

@ -100,7 +100,7 @@ use rustc_middle::middle;
use rustc_middle::mir::interpret::GlobalId;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_span::Span;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
pub use crate::collect::suggest_impl_trait;
@ -139,16 +139,20 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
let _prof_timer = tcx.sess.timer("type_check_crate");
tcx.sess.time("coherence_checking", || {
// When discarding query call results, use an explicit type to indicate
// what we are intending to discard, to help future type-based refactoring.
type R = Result<(), ErrorGuaranteed>;
tcx.hir().par_for_each_module(|module| {
let _ = tcx.ensure().check_mod_type_wf(module);
let _: R = tcx.ensure_ok().check_mod_type_wf(module);
});
for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
let _ = tcx.ensure().coherent_trait(trait_def_id);
let _: R = tcx.ensure_ok().coherent_trait(trait_def_id);
}
// these queries are executed for side-effects (error reporting):
let _ = tcx.ensure().crate_inherent_impls_validity_check(());
let _ = tcx.ensure().crate_inherent_impls_overlap_check(());
let _: R = tcx.ensure_ok().crate_inherent_impls_validity_check(());
let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(());
});
if tcx.features().rustc_attrs() {
@ -167,12 +171,12 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
tcx.hir().par_body_owners(|item_def_id| {
let def_kind = tcx.def_kind(item_def_id);
match def_kind {
DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id),
DefKind::Static { .. } => tcx.ensure_ok().eval_static_initializer(item_def_id),
DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty());
let cid = GlobalId { instance, promoted: None };
let typing_env = ty::TypingEnv::fully_monomorphized();
tcx.ensure().eval_to_const_value_raw(typing_env.as_query_input(cid));
tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid));
}
_ => (),
}
@ -185,11 +189,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
tcx.hir().par_body_owners(|item_def_id| {
let def_kind = tcx.def_kind(item_def_id);
if !matches!(def_kind, DefKind::AnonConst) {
tcx.ensure().typeck(item_def_id);
tcx.ensure_ok().typeck(item_def_id);
}
});
tcx.ensure().check_unused_traits(());
tcx.ensure_ok().check_unused_traits(());
}
/// Lower a [`hir::Ty`] to a [`Ty`].

View file

@ -49,7 +49,7 @@ pub(crate) fn check_legal_trait_for_method_call(
};
return Err(tcx.dcx().emit_err(errors::ExplicitDestructorCall { span, sugg }));
}
tcx.ensure().coherent_trait(trait_id)
tcx.ensure_ok().coherent_trait(trait_id)
}
#[derive(Debug)]

View file

@ -50,7 +50,6 @@ use rustc_infer::traits::{
IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation,
PredicateObligations,
};
use rustc_middle::lint::in_external_macro;
use rustc_middle::span_bug;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::adjustment::{
@ -1937,7 +1936,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
cond_expr.span.desugaring_kind(),
None | Some(DesugaringKind::WhileLoop)
)
&& !in_external_macro(fcx.tcx.sess, cond_expr.span)
&& !cond_expr.span.in_external_macro(fcx.tcx.sess.source_map())
&& !matches!(
cond_expr.kind,
hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))

View file

@ -1,4 +1,4 @@
use rustc_errors::{Applicability, Diag, MultiSpan};
use rustc_errors::{Applicability, Diag, MultiSpan, listify};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::intravisit::Visitor;
@ -1016,18 +1016,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
self.tcx.def_path_str(candidate.item.container_id(self.tcx))
),
[.., last] if other_methods_in_scope.len() < 5 => {
_ if other_methods_in_scope.len() < 5 => {
format!(
"the methods of the same name on {} and `{}`",
other_methods_in_scope[..other_methods_in_scope.len() - 1]
.iter()
.map(|c| format!(
"`{}`",
self.tcx.def_path_str(c.item.container_id(self.tcx))
))
.collect::<Vec<String>>()
.join(", "),
self.tcx.def_path_str(last.item.container_id(self.tcx))
"the methods of the same name on {}",
listify(
&other_methods_in_scope[..other_methods_in_scope.len() - 1],
|c| format!("`{}`", self.tcx.def_path_str(c.item.container_id(self.tcx)))
)
.unwrap_or_default(),
)
}
_ => format!(

View file

@ -11,7 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::unord::UnordMap;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize,
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize,
struct_span_code_err,
};
use rustc_hir::def::{CtorKind, DefKind, Res};
@ -2188,13 +2188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if !missing_mandatory_fields.is_empty() {
let s = pluralize!(missing_mandatory_fields.len());
let fields: Vec<_> =
missing_mandatory_fields.iter().map(|f| format!("`{f}`")).collect();
let fields = match &fields[..] {
[] => unreachable!(),
[only] => only.to_string(),
[start @ .., last] => format!("{} and {last}", start.join(", ")),
};
let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap();
self.dcx()
.struct_span_err(
span.shrink_to_hi(),
@ -2551,25 +2545,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.partition(|field| field.2);
err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field");
if !remaining_private_fields.is_empty() {
let remaining_private_fields_len = remaining_private_fields.len();
let names = match &remaining_private_fields
.iter()
.map(|(name, _, _)| name)
.collect::<Vec<_>>()[..]
{
_ if remaining_private_fields_len > 6 => String::new(),
[name] => format!("`{name}` "),
[names @ .., last] => {
let names = names.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
format!("{} and `{last}` ", names.join(", "))
}
[] => bug!("expected at least one private field to report"),
let names = if remaining_private_fields.len() > 6 {
String::new()
} else {
format!(
"{} ",
listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`"))
.expect("expected at least one private field to report")
)
};
err.note(format!(
"{}private field{s} {names}that {were} not provided",
if used_fields.is_empty() { "" } else { "...and other " },
s = pluralize!(remaining_private_fields_len),
were = pluralize!("was", remaining_private_fields_len),
s = pluralize!(remaining_private_fields.len()),
were = pluralize!("was", remaining_private_fields.len()),
));
}

View file

@ -4,8 +4,7 @@ use itertools::Itertools;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an,
display_list_with_comma_and, pluralize,
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, listify, pluralize,
};
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
@ -2462,7 +2461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param.span,
format!(
"{} need{} to match the {} type of this parameter",
display_list_with_comma_and(&other_param_matched_names),
listify(&other_param_matched_names, |n| n.to_string())
.unwrap_or_default(),
pluralize!(if other_param_matched_names.len() == 1 {
0
} else {
@ -2477,7 +2477,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!(
"this parameter needs to match the {} type of {}",
matched_ty,
display_list_with_comma_and(&other_param_matched_names),
listify(&other_param_matched_names, |n| n.to_string())
.unwrap_or_default(),
),
);
}
@ -2523,7 +2524,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
generic_param.span,
format!(
"{} {} reference this parameter `{}`",
display_list_with_comma_and(&param_idents_matching),
listify(&param_idents_matching, |n| n.to_string())
.unwrap_or_default(),
if param_idents_matching.len() == 2 { "both" } else { "all" },
generic_param.name.ident().name,
),

View file

@ -4,7 +4,7 @@ use core::iter;
use hir::def_id::LocalDefId;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_data_structures::packed::Pu128;
use rustc_errors::{Applicability, Diag, MultiSpan};
use rustc_errors::{Applicability, Diag, MultiSpan, listify};
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
@ -14,7 +14,6 @@ use rustc_hir::{
};
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_hir_analysis::suggest_impl_trait;
use rustc_middle::lint::in_external_macro;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::span_bug;
use rustc_middle::ty::print::with_no_trimmed_paths;
@ -770,7 +769,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the expression is from an external macro, then do not suggest
// adding a semicolon, because there's nowhere to put it.
// See issue #81943.
&& !in_external_macro(self.tcx.sess, expression.span) =>
&& !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
{
if needs_block {
err.multipart_suggestion(
@ -1836,16 +1835,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error.obligation.predicate,
));
}
[errors @ .., last] => {
_ => {
diag.help(format!(
"`Clone` is not implemented because the following trait bounds \
could not be satisfied: {} and `{}`",
errors
.iter()
.map(|e| format!("`{}`", e.obligation.predicate))
.collect::<Vec<_>>()
.join(", "),
last.obligation.predicate,
could not be satisfied: {}",
listify(&errors, |e| format!("`{}`", e.obligation.predicate))
.unwrap(),
));
}
}
@ -2265,7 +2260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
) -> bool {
if in_external_macro(self.tcx.sess, expr.span) {
if expr.span.in_external_macro(self.tcx.sess.source_map()) {
return false;
}
if let ty::Adt(expected_adt, args) = expected.kind() {
@ -2593,14 +2588,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)> {
let sess = self.sess();
let sp = expr.span;
let sm = sess.source_map();
// If the span is from an external macro, there's no suggestion we can make.
if in_external_macro(sess, sp) {
if sp.in_external_macro(sm) {
return None;
}
let sm = sess.source_map();
let replace_prefix = |s: &str, old: &str, new: &str| {
s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
};

View file

@ -5,6 +5,7 @@
use core::ops::ControlFlow;
use std::borrow::Cow;
use std::path::PathBuf;
use hir::Expr;
use rustc_ast::ast::Mutability;
@ -362,14 +363,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
let mut file = None;
let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file);
let mut err = struct_span_code_err!(
self.dcx(),
rcvr_expr.span,
E0599,
"cannot write into `{}`",
ty_str
self.tcx.short_string(rcvr_ty, &mut file),
);
*err.long_ty_path() = file;
err.span_note(
rcvr_expr.span,
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
@ -380,11 +381,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"a writer is needed before this format string",
);
};
if let Some(file) = file {
err.note(format!("the full type name has been written to '{}'", file.display()));
err.note("consider using `--verbose` to print the full type name to the console");
}
err
}
@ -595,7 +591,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string()))
} else {
(
tcx.short_ty_string(rcvr_ty, &mut ty_file),
tcx.short_string(rcvr_ty, &mut ty_file),
with_forced_trimmed_paths!(rcvr_ty.to_string()),
)
};
@ -624,6 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
item_name,
&short_ty_str,
&mut ty_file,
) {
return guar;
}
@ -635,6 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_kind,
item_name,
&short_ty_str,
&mut ty_file,
) {
return guar;
}
@ -728,10 +726,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty_str = short_ty_str;
}
if let Some(file) = ty_file {
err.note(format!("the full type name has been written to '{}'", file.display(),));
err.note("consider using `--verbose` to print the full type name to the console");
}
if rcvr_ty.references_error() {
err.downgrade_to_delayed_bug();
}
@ -1314,7 +1308,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
let actual_prefix = rcvr_ty.prefix_string(self.tcx);
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
let mut long_ty_file = None;
let (primary_message, label, notes) = if unimplemented_traits.len() == 1
&& unimplemented_traits_only
{
@ -1329,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let OnUnimplementedNote { message, label, notes, .. } = self
.err_ctxt()
.on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
.on_unimplemented_note(trait_ref, &obligation, &mut ty_file);
(message, label, notes)
})
.unwrap()
@ -1343,15 +1336,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
});
err.primary_message(primary_message);
if let Some(file) = long_ty_file {
err.note(format!(
"the full name for the type has been written to '{}'",
file.display(),
));
err.note(
"consider using `--verbose` to print the full type name to the console",
);
}
if let Some(label) = label {
custom_span_label = true;
err.span_label(span, label);
@ -2403,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
item_name: Ident,
ty_str: &str,
long_ty_path: &mut Option<PathBuf>,
) -> Result<(), ErrorGuaranteed> {
if let SelfSource::MethodCall(expr) = source {
for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
@ -2460,7 +2445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
if pick.is_ok() {
let range_span = parent_expr.span.with_hi(expr.span.hi());
return Err(self.dcx().emit_err(errors::MissingParenthesesInRange {
let mut err = self.dcx().create_err(errors::MissingParenthesesInRange {
span,
ty_str: ty_str.to_string(),
method_name: item_name.as_str().to_string(),
@ -2469,7 +2454,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
left: range_span.shrink_to_lo(),
right: range_span.shrink_to_hi(),
}),
}));
});
*err.long_ty_path() = long_ty_path.take();
return Err(err.emit());
}
}
}
@ -2486,6 +2473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_kind: &str,
item_name: Ident,
ty_str: &str,
long_ty_path: &mut Option<PathBuf>,
) -> Result<(), ErrorGuaranteed> {
let found_candidate = all_traits(self.tcx)
.into_iter()
@ -2526,6 +2514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name,
ty_str
);
*err.long_ty_path() = long_ty_path.take();
let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
match expr.kind {
ExprKind::Lit(lit) => {

View file

@ -26,7 +26,6 @@ use rustc_macros::extension;
pub use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::bug;
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::select;
pub use rustc_middle::ty::IntVarValue;
@ -46,6 +45,7 @@ use tracing::{debug, instrument};
use type_variable::TypeVariableOrigin;
use crate::infer::region_constraints::UndoLog;
use crate::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
use crate::traits::{
self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine,
};
@ -64,6 +64,7 @@ pub mod relate;
pub mod resolve;
pub(crate) mod snapshot;
mod type_variable;
mod unify_key;
/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper
/// around `PredicateObligations<'tcx>`, but it has one important property:

View file

@ -8,7 +8,6 @@ use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
use rustc_index::IndexVec;
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::infer::unify_key::{RegionVariableValue, RegionVidKey};
use rustc_middle::ty::{self, ReBound, ReStatic, ReVar, Region, RegionVid, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use tracing::{debug, instrument};
@ -17,6 +16,7 @@ use self::CombineMapType::*;
use self::UndoLog::*;
use super::{MiscVariable, RegionVariableOrigin, Rollback, SubregionOrigin};
use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
use crate::infer::unify_key::{RegionVariableValue, RegionVidKey};
mod leak_check;

View file

@ -4,7 +4,6 @@ use rustc_data_structures::sso::SsoHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def_id::DefId;
use rustc_middle::bug;
use rustc_middle::infer::unify_key::ConstVariableValue;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::visit::MaxUniverse;
use rustc_middle::ty::{
@ -18,6 +17,7 @@ use super::{
PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
};
use crate::infer::type_variable::TypeVariableValue;
use crate::infer::unify_key::ConstVariableValue;
use crate::infer::{InferCtxt, RegionVariableOrigin, relate};
impl<'tcx> InferCtxt<'tcx> {

View file

@ -1,7 +1,6 @@
use std::ops::Range;
use rustc_data_structures::{snapshot_vec as sv, unify as ut};
use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
use rustc_type_ir::visit::TypeVisitableExt;
@ -10,6 +9,7 @@ use ut::UnifyKey;
use super::VariableLengths;
use crate::infer::type_variable::TypeVariableOrigin;
use crate::infer::unify_key::{ConstVariableValue, ConstVidKey};
use crate::infer::{ConstVariableOrigin, InferCtxt, RegionVariableOrigin, UnificationTable};
fn vars_since_snapshot<'tcx, T>(

View file

@ -2,10 +2,10 @@ use std::marker::PhantomData;
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::{snapshot_vec as sv, unify as ut};
use rustc_middle::infer::unify_key::{ConstVidKey, RegionVidKey};
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
use tracing::debug;
use crate::infer::unify_key::{ConstVidKey, RegionVidKey};
use crate::infer::{InferCtxtInner, region_constraints, type_variable};
use crate::traits;

View file

@ -2,23 +2,18 @@ use std::cmp;
use std::marker::PhantomData;
use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
use rustc_middle::{bug, ty};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use crate::ty::{self, Ty, TyCtxt};
pub trait ToType {
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
}
#[derive(Copy, Clone, Debug)]
pub enum RegionVariableValue<'tcx> {
pub(crate) enum RegionVariableValue<'tcx> {
Known { value: ty::Region<'tcx> },
Unknown { universe: ty::UniverseIndex },
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey<'tcx> {
pub(crate) struct RegionVidKey<'tcx> {
pub vid: ty::RegionVid,
pub phantom: PhantomData<RegionVariableValue<'tcx>>,
}
@ -44,7 +39,8 @@ impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
}
}
pub struct RegionUnificationError;
pub(crate) struct RegionUnificationError;
impl<'tcx> UnifyValue for RegionVariableValue<'tcx> {
type Error = RegionUnificationError;
@ -100,7 +96,7 @@ pub struct ConstVariableOrigin {
}
#[derive(Copy, Clone, Debug)]
pub enum ConstVariableValue<'tcx> {
pub(crate) enum ConstVariableValue<'tcx> {
Known { value: ty::Const<'tcx> },
Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex },
}
@ -108,7 +104,7 @@ pub enum ConstVariableValue<'tcx> {
impl<'tcx> ConstVariableValue<'tcx> {
/// If this value is known, returns the const it is known to be.
/// Otherwise, `None`.
pub fn known(&self) -> Option<ty::Const<'tcx>> {
pub(crate) fn known(&self) -> Option<ty::Const<'tcx>> {
match *self {
ConstVariableValue::Unknown { .. } => None,
ConstVariableValue::Known { value } => Some(value),
@ -117,7 +113,7 @@ impl<'tcx> ConstVariableValue<'tcx> {
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct ConstVidKey<'tcx> {
pub(crate) struct ConstVidKey<'tcx> {
pub vid: ty::ConstVid,
pub phantom: PhantomData<ty::Const<'tcx>>,
}

View file

@ -832,20 +832,20 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
sess.time("misc_checking_1", || {
parallel!(
{
sess.time("looking_for_entry_point", || tcx.ensure().entry_fn(()));
sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(()));
sess.time("looking_for_derive_registrar", || {
tcx.ensure().proc_macro_decls_static(())
tcx.ensure_ok().proc_macro_decls_static(())
});
CStore::from_tcx(tcx).report_unused_deps(tcx);
},
{
tcx.hir().par_for_each_module(|module| {
tcx.ensure().check_mod_loops(module);
tcx.ensure().check_mod_attrs(module);
tcx.ensure().check_mod_naked_functions(module);
tcx.ensure().check_mod_unstable_api_usage(module);
tcx.ensure_ok().check_mod_loops(module);
tcx.ensure_ok().check_mod_attrs(module);
tcx.ensure_ok().check_mod_naked_functions(module);
tcx.ensure_ok().check_mod_unstable_api_usage(module);
});
},
{
@ -858,8 +858,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
// since they might not otherwise get called.
// This marks the corresponding crate-level attributes
// as used, and ensures that their values are valid.
tcx.ensure().limits(());
tcx.ensure().stability_index(());
tcx.ensure_ok().limits(());
tcx.ensure_ok().stability_index(());
}
);
});
@ -868,7 +868,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
sess.time("MIR_coroutine_by_move_body", || {
tcx.hir().par_body_owners(|def_id| {
if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) {
tcx.ensure_with_value().coroutine_by_move_body_def_id(def_id);
tcx.ensure_done().coroutine_by_move_body_def_id(def_id);
}
});
});
@ -883,13 +883,13 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
tcx.hir().par_body_owners(|def_id| {
// Run unsafety check because it's responsible for stealing and
// deallocating THIR.
tcx.ensure().check_unsafety(def_id);
tcx.ensure().mir_borrowck(def_id)
tcx.ensure_ok().check_unsafety(def_id);
tcx.ensure_ok().mir_borrowck(def_id)
});
});
sess.time("MIR_effect_checking", || {
tcx.hir().par_body_owners(|def_id| {
tcx.ensure().has_ffi_unwind_calls(def_id);
tcx.ensure_ok().has_ffi_unwind_calls(def_id);
// If we need to codegen, ensure that we emit all errors from
// `mir_drops_elaborated_and_const_checked` now, to avoid discovering
@ -897,15 +897,15 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
if tcx.sess.opts.output_types.should_codegen()
|| tcx.hir().body_const_context(def_id).is_some()
{
tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id);
}
});
});
sess.time("coroutine_obligations", || {
tcx.hir().par_body_owners(|def_id| {
if tcx.is_coroutine(def_id.to_def_id()) {
tcx.ensure().mir_coroutine_witnesses(def_id);
tcx.ensure().check_coroutine_obligations(
tcx.ensure_ok().mir_coroutine_witnesses(def_id);
tcx.ensure_ok().check_coroutine_obligations(
tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
);
}
@ -950,15 +950,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
sess.time("misc_checking_3", || {
parallel!(
{
tcx.ensure().effective_visibilities(());
tcx.ensure_ok().effective_visibilities(());
parallel!(
{
tcx.ensure().check_private_in_public(());
tcx.ensure_ok().check_private_in_public(());
},
{
tcx.hir()
.par_for_each_module(|module| tcx.ensure().check_mod_deathness(module));
tcx.hir().par_for_each_module(|module| {
tcx.ensure_ok().check_mod_deathness(module)
});
},
{
sess.time("lint_checking", || {
@ -966,14 +967,14 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
});
},
{
tcx.ensure().clashing_extern_declarations(());
tcx.ensure_ok().clashing_extern_declarations(());
}
);
},
{
sess.time("privacy_checking_modules", || {
tcx.hir().par_for_each_module(|module| {
tcx.ensure().check_mod_privacy(module);
tcx.ensure_ok().check_mod_privacy(module);
});
});
}
@ -981,7 +982,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
// This check has to be run after all lints are done processing. We don't
// define a lint filter, as all lint checks should have finished at this point.
sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None));
sess.time("check_lint_expectations", || tcx.ensure_ok().check_expectations(None));
// This query is only invoked normally if a diagnostic is emitted that needs any
// diagnostic item. If the crate compiles without checking any diagnostic items,
@ -1006,7 +1007,7 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
)
}) =>
{
tcx.ensure().trigger_delayed_bug(def_id);
tcx.ensure_ok().trigger_delayed_bug(def_id);
}
// Bare `#[rustc_error]`.

View file

@ -29,7 +29,6 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_hir::intravisit::FnKind as HirFnKind;
use rustc_hir::{Body, FnDecl, GenericParamKind, PatKind, PredicateOrigin};
use rustc_middle::bug;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
@ -2029,7 +2028,7 @@ impl ExplicitOutlivesRequirements {
}
let span = bound.span().find_ancestor_inside(predicate_span)?;
if in_external_macro(tcx.sess, span) {
if span.in_external_macro(tcx.sess.source_map()) {
return None;
}

View file

@ -135,7 +135,7 @@ pub(super) fn unexpected_cfg_name(
};
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span);
let is_from_external_macro = name_span.in_external_macro(sess.source_map());
let mut is_feature_cfg = name == sym::feature;
let code_sugg = if is_feature_cfg && is_from_cargo {
@ -281,7 +281,7 @@ pub(super) fn unexpected_cfg_value(
.collect();
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span);
let is_from_external_macro = name_span.in_external_macro(sess.source_map());
// Show the full list if all possible values for a given name, but don't do it
// for names as the possibilities could be very long

View file

@ -458,7 +458,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
|| {
tcx.sess.time("module_lints", || {
// Run per-module lints
tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module));
tcx.hir().par_for_each_module(|module| tcx.ensure_ok().lint_mod(module));
});
},
);

View file

@ -2,7 +2,6 @@ use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_hir::{self as hir, LangItem};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::lint::in_external_macro;
use rustc_middle::{bug, ty};
use rustc_parse_format::{ParseMode, Parser, Piece};
use rustc_session::lint::FutureIncompatibilityReason;
@ -100,7 +99,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
let (span, panic, symbol) = panic_call(cx, f);
if in_external_macro(cx.sess(), span) {
if span.in_external_macro(cx.sess().source_map()) {
// Nothing that can be done about it in the current crate.
return;
}
@ -229,14 +228,15 @@ fn check_panic_str<'tcx>(
let (span, _, _) = panic_call(cx, f);
if in_external_macro(cx.sess(), span) && in_external_macro(cx.sess(), arg.span) {
let sm = cx.sess().source_map();
if span.in_external_macro(sm) && arg.span.in_external_macro(sm) {
// Nothing that can be done about it in the current crate.
return;
}
let fmt_span = arg.span.source_callsite();
let (snippet, style) = match cx.sess().psess.source_map().span_to_snippet(fmt_span) {
let (snippet, style) = match sm.span_to_snippet(fmt_span) {
Ok(snippet) => {
// Count the number of `#`s between the `r` and `"`.
let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
@ -283,7 +283,7 @@ fn check_panic_str<'tcx>(
/// Given the span of `some_macro!(args);`, gives the span of `(` and `)`,
/// and the type of (opening) delimiter used.
fn find_delimiters(cx: &LateContext<'_>, span: Span) -> Option<(Span, Span, char)> {
let snippet = cx.sess().psess.source_map().span_to_snippet(span).ok()?;
let snippet = cx.sess().source_map().span_to_snippet(span).ok()?;
let (open, open_ch) = snippet.char_indices().find(|&(_, c)| "([{".contains(c))?;
let close = snippet.rfind(|c| ")]}".contains(c))?;
Some((

View file

@ -42,6 +42,23 @@ macro_rules! pluralize {
};
}
/// Grammatical tool for displaying messages to end users in a nice form.
///
/// Take a list of items and a function to turn those items into a `String`, and output a display
/// friendly comma separated list of those items.
// FIXME(estebank): this needs to be changed to go through the translation machinery.
pub fn listify<T>(list: &[T], fmt: impl Fn(&T) -> String) -> Option<String> {
Some(match list {
[only] => fmt(&only),
[others @ .., last] => format!(
"{} and {}",
others.iter().map(|i| fmt(i)).collect::<Vec<_>>().join(", "),
fmt(&last),
),
[] => return None,
})
}
/// Indicates the confidence in the correctness of a suggestion.
///
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion

View file

@ -118,11 +118,17 @@ struct QueryModifiers {
/// Generate a `feed` method to set the query's value from another query.
feedable: Option<Ident>,
/// Forward the result on ensure if the query gets recomputed, and
/// return `Ok(())` otherwise. Only applicable to queries returning
/// `Result<T, ErrorGuaranteed>`. The `T` is not returned from `ensure`
/// invocations.
ensure_forwards_result_if_red: Option<Ident>,
/// When this query is called via `tcx.ensure_ok()`, it returns
/// `Result<(), ErrorGuaranteed>` instead of `()`. If the query needs to
/// be executed, and that execution returns an error, the error result is
/// returned to the caller.
///
/// If execution is skipped, a synthetic `Ok(())` is returned, on the
/// assumption that a query with all-green inputs must have succeeded.
///
/// Can only be applied to queries with a return value of
/// `Result<_, ErrorGuaranteed>`.
return_result_from_ensure_ok: Option<Ident>,
}
fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
@ -138,7 +144,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
let mut depth_limit = None;
let mut separate_provide_extern = None;
let mut feedable = None;
let mut ensure_forwards_result_if_red = None;
let mut return_result_from_ensure_ok = None;
while !input.is_empty() {
let modifier: Ident = input.parse()?;
@ -200,8 +206,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
try_insert!(separate_provide_extern = modifier);
} else if modifier == "feedable" {
try_insert!(feedable = modifier);
} else if modifier == "ensure_forwards_result_if_red" {
try_insert!(ensure_forwards_result_if_red = modifier);
} else if modifier == "return_result_from_ensure_ok" {
try_insert!(return_result_from_ensure_ok = modifier);
} else {
return Err(Error::new(modifier.span(), "unknown query modifier"));
}
@ -222,7 +228,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
depth_limit,
separate_provide_extern,
feedable,
ensure_forwards_result_if_red,
return_result_from_ensure_ok,
})
}
@ -354,7 +360,7 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
eval_always,
depth_limit,
separate_provide_extern,
ensure_forwards_result_if_red,
return_result_from_ensure_ok,
);
if modifiers.cache.is_some() {

View file

@ -165,7 +165,7 @@ macro_rules! provide_one {
// doesn't need to do this (and can't, as it would cause a query cycle).
use rustc_middle::dep_graph::dep_kinds;
if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() {
$tcx.ensure().crate_hash($def_id.krate);
$tcx.ensure_ok().crate_hash($def_id.krate);
}
let cdata = rustc_data_structures::sync::FreezeReadGuard::map(CStore::from_tcx($tcx), |c| {

View file

@ -2191,13 +2191,13 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
if encode_const {
tcx.ensure_with_value().mir_for_ctfe(def_id);
tcx.ensure_done().mir_for_ctfe(def_id);
}
if encode_opt {
tcx.ensure_with_value().optimized_mir(def_id);
tcx.ensure_done().optimized_mir(def_id);
}
if encode_opt || encode_const {
tcx.ensure_with_value().promoted_mir(def_id);
tcx.ensure_done().promoted_mir(def_id);
}
})
}

View file

@ -1,2 +1 @@
pub mod canonical;
pub mod unify_key;

View file

@ -8,8 +8,7 @@ use rustc_macros::{Decodable, Encodable, HashStable};
use rustc_session::Session;
use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::{DUMMY_SP, DesugaringKind, Span, Symbol, kw};
use rustc_span::{DUMMY_SP, Span, Symbol, kw};
use tracing::instrument;
use crate::ty::TyCtxt;
@ -201,7 +200,7 @@ impl LintExpectation {
}
}
pub fn explain_lint_level_source(
fn explain_lint_level_source(
lint: &'static Lint,
level: Level,
src: LintLevelSource,
@ -325,7 +324,7 @@ pub fn lint_level(
// If this code originates in a foreign macro, aka something that this crate
// did not itself author, then it's likely that there's nothing this crate
// can do about it. We probably want to skip the lint entirely.
if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
if err.span.primary_spans().iter().any(|s| s.in_external_macro(sess.source_map())) {
// Any suggestions made here are likely to be incorrect, so anything we
// emit shouldn't be automatically fixed by rustfix.
err.disable_suggestions();
@ -422,36 +421,3 @@ pub fn lint_level(
}
lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
}
/// Returns whether `span` originates in a foreign crate's external macro.
///
/// This is used to test whether a lint should not even begin to figure out whether it should
/// be reported on the current node.
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
let expn_data = span.ctxt().outer_expn_data();
match expn_data.kind {
ExpnKind::Root
| ExpnKind::Desugaring(
DesugaringKind::ForLoop
| DesugaringKind::WhileLoop
| DesugaringKind::OpaqueTy
| DesugaringKind::Async
| DesugaringKind::Await,
) => false,
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
ExpnKind::Macro(MacroKind::Bang, _) => {
// Dummy span for the `def_site` means it's an external macro.
expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
}
ExpnKind::Macro { .. } => true, // definitely a plugin
}
}
/// Return whether `span` is generated by `async` or `await`.
pub fn is_from_async_await(span: Span) -> bool {
let expn_data = span.ctxt().outer_expn_data();
match expn_data.kind {
ExpnKind::Desugaring(DesugaringKind::Async | DesugaringKind::Await) => true,
_ => false,
}
}

View file

@ -9,7 +9,7 @@ use super::{
ReportedErrorInfo,
};
use crate::mir;
use crate::query::TyCtxtEnsure;
use crate::query::TyCtxtEnsureOk;
use crate::ty::visit::TypeVisitableExt;
use crate::ty::{self, GenericArgs, TyCtxt};
@ -198,7 +198,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
impl<'tcx> TyCtxtEnsure<'tcx> {
impl<'tcx> TyCtxtEnsureOk<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.

View file

@ -92,51 +92,88 @@ impl<'tcx> MonoItem<'tcx> {
}
pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
let generate_cgu_internal_copies =
(tcx.sess.opts.optimize != OptLevel::No) && !tcx.sess.link_dead_code();
// The case handling here is written in the same style as cross_crate_inlinable, we first
// handle the cases where we must use a particular instantiation mode, then cascade down
// through a sequence of heuristics.
match *self {
MonoItem::Fn(ref instance) => {
let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id);
// If this function isn't inlined or otherwise has an extern
// indicator, then we'll be creating a globally shared version.
let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
if codegen_fn_attrs.contains_extern_indicator()
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
|| !instance.def.generates_cgu_internal_copy(tcx)
|| Some(instance.def_id()) == entry_def_id
{
return InstantiationMode::GloballyShared { may_conflict: false };
}
// The first thing we do is detect MonoItems which we must instantiate exactly once in the
// whole program.
if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
&& self.is_generic_fn()
{
// Upgrade inline(never) to a globally shared instance.
return InstantiationMode::GloballyShared { may_conflict: true };
}
// At this point we don't have explicit linkage and we're an
// inlined function. If this crate's build settings permit,
// we'll be creating a local copy per CGU.
if generate_cgu_internal_copies {
return InstantiationMode::LocalCopy;
}
// Finally, if this is `#[inline(always)]` we're sure to respect
// that with an inline copy per CGU, but otherwise we'll be
// creating one copy of this `#[inline]` function which may
// conflict with upstream crates as it could be an exported
// symbol.
if tcx.codegen_fn_attrs(instance.def_id()).inline.always() {
InstantiationMode::LocalCopy
} else {
InstantiationMode::GloballyShared { may_conflict: true }
}
}
// Statics and global_asm! must be instantiated exactly once.
let instance = match *self {
MonoItem::Fn(instance) => instance,
MonoItem::Static(..) | MonoItem::GlobalAsm(..) => {
InstantiationMode::GloballyShared { may_conflict: false }
return InstantiationMode::GloballyShared { may_conflict: false };
}
};
// Similarly, the executable entrypoint must be instantiated exactly once.
if let Some((entry_def_id, _)) = tcx.entry_fn(()) {
if instance.def_id() == entry_def_id {
return InstantiationMode::GloballyShared { may_conflict: false };
}
}
// If the function is #[naked] or contains any other attribute that requires exactly-once
// instantiation:
let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
if codegen_fn_attrs.contains_extern_indicator()
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
{
return InstantiationMode::GloballyShared { may_conflict: false };
}
// FIXME: The logic for which functions are permitted to get LocalCopy is actually spread
// across 4 functions:
// * cross_crate_inlinable(def_id)
// * InstanceKind::requires_inline
// * InstanceKind::generate_cgu_internal_copy
// * MonoItem::instantiation_mode
// Since reachable_non_generics calls InstanceKind::generates_cgu_internal_copy to decide
// which symbols this crate exports, we are obligated to only generate LocalCopy when
// generates_cgu_internal_copy returns true.
if !instance.def.generates_cgu_internal_copy(tcx) {
return InstantiationMode::GloballyShared { may_conflict: false };
}
// Beginning of heuristics. The handling of link-dead-code and inline(always) are QoL only,
// the compiler should not crash and linkage should work, but codegen may be undesirable.
// -Clink-dead-code was given an unfortunate name; the point of the flag is to assist
// coverage tools which rely on having every function in the program appear in the
// generated code. If we select LocalCopy, functions which are not used because they are
// missing test coverage will disappear from such coverage reports, defeating the point.
// Note that -Cinstrument-coverage does not require such assistance from us, only coverage
// tools implemented without compiler support ironically require a special compiler flag.
if tcx.sess.link_dead_code() {
return InstantiationMode::GloballyShared { may_conflict: true };
}
// To ensure that #[inline(always)] can be inlined as much as possible, especially in unoptimized
// builds, we always select LocalCopy.
if codegen_fn_attrs.inline.always() {
return InstantiationMode::LocalCopy;
}
// #[inline(never)] functions in general are poor candidates for inlining and thus since
// LocalCopy generally increases code size for the benefit of optimizations from inlining,
// we want to give them GloballyShared codegen.
// The slight problem is that generic functions need to always support cross-crate
// compilation, so all previous stages of the compiler are obligated to treat generic
// functions the same as those that unconditionally get LocalCopy codegen. It's only when
// we get here that we can at least not codegen a #[inline(never)] generic function in all
// of our CGUs.
if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
&& self.is_generic_fn()
{
return InstantiationMode::GloballyShared { may_conflict: true };
}
// The fallthrough case is to generate LocalCopy for all optimized builds, and
// GloballyShared with conflict prevention when optimizations are disabled.
match tcx.sess.opts.optimize {
OptLevel::No => InstantiationMode::GloballyShared { may_conflict: true },
_ => InstantiationMode::LocalCopy,
}
}

View file

@ -91,7 +91,7 @@ pub use keys::{AsLocalKey, Key, LocalCrate};
pub mod on_disk_cache;
#[macro_use]
pub mod plumbing;
pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue};
pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk};
// Each of these queries corresponds to a function pointer field in the
// `Providers` struct for requesting a value of that type, and a method
@ -1087,7 +1087,7 @@ rustc_queries! {
query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> {
desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) }
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
/// Caches `CoerceUnsized` kinds for impls on custom types.
@ -1095,7 +1095,7 @@ rustc_queries! {
desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
@ -1110,7 +1110,7 @@ rustc_queries! {
query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> {
desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
/// Borrow-checks the function body. If this is a closure, returns
@ -1140,7 +1140,7 @@ rustc_queries! {
/// </div>
query crate_inherent_impls_validity_check(_: ()) -> Result<(), ErrorGuaranteed> {
desc { "check for inherent impls that should not be defined in crate" }
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
/// Checks all types in the crate for overlap in their inherent impls. Reports errors.
@ -1152,7 +1152,7 @@ rustc_queries! {
/// </div>
query crate_inherent_impls_overlap_check(_: ()) -> Result<(), ErrorGuaranteed> {
desc { "check for overlap between inherent impls defined in this crate" }
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
/// Checks whether all impls in the crate pass the overlap check, returning
@ -1162,7 +1162,7 @@ rustc_queries! {
"checking whether impl `{}` follows the orphan rules",
tcx.def_path_str(key),
}
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
/// Check whether the function has any recursion that could cause the inliner to trigger
@ -1479,7 +1479,7 @@ rustc_queries! {
query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> {
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
cache_on_disk_if { true }
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
query dyn_compatibility_violations(trait_id: DefId) -> &'tcx [DynCompatibilityViolation] {
desc { |tcx| "determining dyn-compatibility of trait `{}`", tcx.def_path_str(trait_id) }
@ -1715,12 +1715,12 @@ rustc_queries! {
query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) }
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
query enforce_impl_non_lifetime_params_are_constrained(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { |tcx| "checking that `{}`'s generics are constrained by the impl header", tcx.def_path_str(key) }
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
// The `DefId`s of all non-generic functions and statics in the given crate
@ -2442,7 +2442,7 @@ rustc_queries! {
/// Any other def id will ICE.
query compare_impl_item(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { |tcx| "checking assoc item `{}` is compatible with trait definition", tcx.def_path_str(key) }
ensure_forwards_result_if_red
return_result_from_ensure_ok
}
query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {

View file

@ -88,30 +88,68 @@ impl<'tcx> Deref for TyCtxtAt<'tcx> {
}
#[derive(Copy, Clone)]
pub struct TyCtxtEnsure<'tcx> {
#[must_use]
pub struct TyCtxtEnsureOk<'tcx> {
pub tcx: TyCtxt<'tcx>,
}
#[derive(Copy, Clone)]
pub struct TyCtxtEnsureWithValue<'tcx> {
#[must_use]
pub struct TyCtxtEnsureDone<'tcx> {
pub tcx: TyCtxt<'tcx>,
}
impl<'tcx> TyCtxt<'tcx> {
/// Returns a transparent wrapper for `TyCtxt`, which ensures queries
/// are executed instead of just returning their results.
/// Wrapper that calls queries in a special "ensure OK" mode, for callers
/// that don't need the return value and just want to invoke a query for
/// its potential side-effect of emitting fatal errors.
///
/// This can be more efficient than a normal query call, because if the
/// query's inputs are all green, the call can return immediately without
/// needing to obtain a value (by decoding one from disk or by executing
/// the query).
///
/// (As with all query calls, execution is also skipped if the query result
/// is already cached in memory.)
///
/// ## WARNING
/// A subsequent normal call to the same query might still cause it to be
/// executed! This can occur when the inputs are all green, but the query's
/// result is not cached on disk, so the query must be executed to obtain a
/// return value.
///
/// Therefore, this call mode is not appropriate for callers that want to
/// ensure that the query is _never_ executed in the future.
///
/// ## `return_result_from_ensure_ok`
/// If a query has the `return_result_from_ensure_ok` modifier, calls via
/// `ensure_ok` will instead return `Result<(), ErrorGuaranteed>`. If the
/// query needs to be executed, and execution returns an error, that error
/// is returned to the caller.
#[inline(always)]
pub fn ensure(self) -> TyCtxtEnsure<'tcx> {
TyCtxtEnsure { tcx: self }
pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> {
TyCtxtEnsureOk { tcx: self }
}
/// Returns a transparent wrapper for `TyCtxt`, which ensures queries
/// are executed instead of just returning their results.
/// Wrapper that calls queries in a special "ensure done" mode, for callers
/// that don't need the return value and just want to guarantee that the
/// query won't be executed in the future, by executing it now if necessary.
///
/// This version verifies that the computed result exists in the cache before returning.
/// This is useful for queries that read from a [`Steal`] value, to ensure
/// that they are executed before the query that will steal the value.
///
/// Unlike [`Self::ensure_ok`], a query with all-green inputs will only be
/// skipped if its return value is stored in the disk-cache. This is still
/// more efficient than a regular query, because in that situation the
/// return value doesn't necessarily need to be decoded.
///
/// (As with all query calls, execution is also skipped if the query result
/// is already cached in memory.)
///
/// [`Steal`]: rustc_data_structures::steal::Steal
#[inline(always)]
pub fn ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx> {
TyCtxtEnsureWithValue { tcx: self }
pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> {
TyCtxtEnsureDone { tcx: self }
}
/// Returns a transparent wrapper for `TyCtxt` which uses
@ -193,7 +231,7 @@ macro_rules! query_ensure {
([]$($args:tt)*) => {
query_ensure($($args)*)
};
([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => {
([(return_result_from_ensure_ok) $($rest:tt)*]$($args:tt)*) => {
query_ensure_error_guaranteed($($args)*).map(|_| ())
};
([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
@ -248,15 +286,15 @@ macro_rules! separate_provide_extern_decl {
};
}
macro_rules! ensure_result {
([][$ty:ty]) => {
macro_rules! ensure_ok_result {
( [] ) => {
()
};
([(ensure_forwards_result_if_red) $($rest:tt)*][$ty:ty]) => {
( [(return_result_from_ensure_ok) $($rest:tt)*] ) => {
Result<(), ErrorGuaranteed>
};
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
ensure_result!([$($modifiers)*][$($args)*])
( [$other:tt $($modifiers:tt)*] ) => {
ensure_ok_result!( [$($modifiers)*] )
};
}
@ -383,10 +421,13 @@ macro_rules! define_callbacks {
$($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)*
}
impl<'tcx> TyCtxtEnsure<'tcx> {
impl<'tcx> TyCtxtEnsureOk<'tcx> {
$($(#[$attr])*
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> ensure_result!([$($modifiers)*][$V]) {
pub fn $name(
self,
key: query_helper_param_ty!($($K)*),
) -> ensure_ok_result!([$($modifiers)*]) {
query_ensure!(
[$($modifiers)*]
self.tcx,
@ -398,7 +439,7 @@ macro_rules! define_callbacks {
})*
}
impl<'tcx> TyCtxtEnsureWithValue<'tcx> {
impl<'tcx> TyCtxtEnsureDone<'tcx> {
$($(#[$attr])*
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {

View file

@ -1957,7 +1957,7 @@ impl<'tcx> TyCtxt<'tcx> {
) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap {
// Create a dependency to the crate to be sure we re-execute this when the amount of
// definitions change.
self.ensure().hir_crate(());
self.ensure_ok().hir_crate(());
// Freeze definitions once we start iterating on them, to prevent adding new ones
// while iterating. If some query needs to add definitions, it should be `ensure`d above.
self.untracked.definitions.freeze().def_path_hash_to_def_index_map()

View file

@ -5,7 +5,7 @@ use std::ops::ControlFlow;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, pluralize,
Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, listify, pluralize,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
@ -362,11 +362,8 @@ pub fn suggest_constraining_type_params<'a>(
let n = trait_names.len();
let stable = if all_stable { "" } else { "unstable " };
let trait_ = if all_known { format!("trait{}", pluralize!(n)) } else { String::new() };
format!("{stable}{trait_}{}", match &trait_names[..] {
[t] => format!(" {t}"),
[ts @ .., last] => format!(" {} and {last}", ts.join(", ")),
[] => return false,
},)
let Some(trait_names) = listify(&trait_names, |n| n.to_string()) else { return false };
format!("{stable}{trait_} {trait_names}")
} else {
// We're more explicit when there's a mix of stable and unstable traits.
let mut trait_names = constraints
@ -378,10 +375,9 @@ pub fn suggest_constraining_type_params<'a>(
.collect::<Vec<_>>();
trait_names.sort();
trait_names.dedup();
match &trait_names[..] {
[t] => t.to_string(),
[ts @ .., last] => format!("{} and {last}", ts.join(", ")),
[] => return false,
match listify(&trait_names, |t| t.to_string()) {
Some(names) => names,
None => return false,
}
};
let constraint = constraint.join(" + ");

View file

@ -10,8 +10,8 @@ use rustc_hir::def::{CtorOf, DefKind};
use rustc_macros::extension;
pub use rustc_type_ir::error::ExpectedFound;
use crate::ty::print::{FmtPrinter, PrettyPrinter, with_forced_trimmed_paths};
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::print::{FmtPrinter, Print, with_forced_trimmed_paths};
use crate::ty::{self, Lift, Ty, TyCtxt};
pub type TypeError<'tcx> = rustc_type_ir::error::TypeError<TyCtxt<'tcx>>;
@ -159,8 +159,8 @@ impl<'tcx> Ty<'tcx> {
ty::Error(_) => "type error".into(),
_ => {
let width = tcx.sess.diagnostic_width();
let length_limit = std::cmp::max(width / 4, 15);
format!("`{}`", tcx.ty_string_with_limit(self, length_limit)).into()
let length_limit = std::cmp::max(width / 4, 40);
format!("`{}`", tcx.string_with_limit(self, length_limit)).into()
}
}
}
@ -213,10 +213,14 @@ impl<'tcx> Ty<'tcx> {
}
impl<'tcx> TyCtxt<'tcx> {
pub fn ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String {
pub fn string_with_limit<'a, T>(self, p: T, length_limit: usize) -> String
where
T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy,
<T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
{
let mut type_limit = 50;
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
cx.pretty_print_type(ty)
self.lift(p).expect("could not lift for printing").print(cx)
})
.expect("could not write to `String`");
if regular.len() <= length_limit {
@ -231,7 +235,10 @@ impl<'tcx> TyCtxt<'tcx> {
hir::def::Namespace::TypeNS,
rustc_session::Limit(type_limit),
);
cx.pretty_print_type(ty).expect("could not write to `String`");
self.lift(p)
.expect("could not lift for printing")
.print(&mut cx)
.expect("could not print type");
cx.into_buffer()
});
if short.len() <= length_limit || type_limit == 0 {
@ -242,9 +249,17 @@ impl<'tcx> TyCtxt<'tcx> {
short
}
pub fn short_ty_string(self, ty: Ty<'tcx>, path: &mut Option<PathBuf>) -> String {
/// When calling this after a `Diag` is constructed, the preferred way of doing so is
/// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps
/// the existence of a "long type" anywhere in the diagnostic, so the note telling the user
/// where we wrote the file to is only printed once.
pub fn short_string<'a, T>(self, p: T, path: &mut Option<PathBuf>) -> String
where
T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy + Hash,
<T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
{
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
cx.pretty_print_type(ty)
self.lift(p).expect("could not lift for printing").print(cx)
})
.expect("could not write to `String`");
@ -257,13 +272,13 @@ impl<'tcx> TyCtxt<'tcx> {
if regular.len() <= width * 2 / 3 {
return regular;
}
let short = self.ty_string_with_limit(ty, length_limit);
let short = self.string_with_limit(p, length_limit);
if regular == short {
return regular;
}
// Ensure we create an unique file for the type passed in when we create a file.
let mut s = DefaultHasher::new();
ty.hash(&mut s);
p.hash(&mut s);
let hash = s.finish();
*path = Some(path.take().unwrap_or_else(|| {
self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None)

View file

@ -105,6 +105,10 @@ pub trait Printer<'tcx>: Sized {
args: &[GenericArg<'tcx>],
) -> Result<(), PrintError>;
fn should_truncate(&mut self) -> bool {
false
}
// Defaults (should not be overridden):
#[instrument(skip(self), level = "debug")]

View file

@ -865,7 +865,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
p!(write("{{"));
if !self.tcx().sess.verbose_internals() {
p!("coroutine witness");
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
let span = self.tcx().def_span(did);
p!(write(
@ -887,26 +886,30 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
p!(write("{{"));
if !self.should_print_verbose() {
p!(write("closure"));
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
if self.tcx().sess.opts.unstable_opts.span_free_formats {
p!("@", print_def_path(did.to_def_id(), args));
} else {
let span = self.tcx().def_span(did);
let preference = if with_forced_trimmed_paths() {
FileNameDisplayPreference::Short
} else {
FileNameDisplayPreference::Remapped
};
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
// into MIR. Hence we use the remapped path if available
self.tcx().sess.source_map().span_to_string(span, preference)
));
}
if self.should_truncate() {
write!(self, "@...}}")?;
return Ok(());
} else {
p!(write("@"), print_def_path(did, args));
if let Some(did) = did.as_local() {
if self.tcx().sess.opts.unstable_opts.span_free_formats {
p!("@", print_def_path(did.to_def_id(), args));
} else {
let span = self.tcx().def_span(did);
let preference = if with_forced_trimmed_paths() {
FileNameDisplayPreference::Short
} else {
FileNameDisplayPreference::Remapped
};
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
// into MIR. Hence we use the remapped path if available
self.tcx().sess.source_map().span_to_string(span, preference)
));
}
} else {
p!(write("@"), print_def_path(did, args));
}
}
} else {
p!(print_def_path(did, args));
@ -942,7 +945,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
"coroutine from coroutine-closure should have CoroutineSource::Closure"
),
}
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
if self.tcx().sess.opts.unstable_opts.span_free_formats {
p!("@", print_def_path(did.to_def_id(), args));
@ -1994,7 +1996,6 @@ pub struct FmtPrinterData<'a, 'tcx> {
binder_depth: usize,
printed_type_count: usize,
type_length_limit: Limit,
truncated: bool,
pub region_highlight_mode: RegionHighlightMode<'tcx>,
@ -2046,7 +2047,6 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
binder_depth: 0,
printed_type_count: 0,
type_length_limit,
truncated: false,
region_highlight_mode: RegionHighlightMode::default(),
ty_infer_name_resolver: None,
const_infer_name_resolver: None,
@ -2183,16 +2183,49 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
}
fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
if self.type_length_limit.value_within_limit(self.printed_type_count) {
self.printed_type_count += 1;
self.pretty_print_type(ty)
} else {
self.truncated = true;
write!(self, "...")?;
Ok(())
match ty.kind() {
ty::Tuple(tys) if tys.len() == 0 && self.should_truncate() => {
// Don't truncate `()`.
self.printed_type_count += 1;
self.pretty_print_type(ty)
}
ty::Adt(..)
| ty::Foreign(_)
| ty::Pat(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::UnsafeBinder(..)
| ty::Dynamic(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Tuple(_)
| ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Error(_)
if self.should_truncate() =>
{
// We only truncate types that we know are likely to be much longer than 3 chars.
// There's no point in replacing `i32` or `!`.
write!(self, "...")?;
Ok(())
}
_ => {
self.printed_type_count += 1;
self.pretty_print_type(ty)
}
}
}
fn should_truncate(&mut self) -> bool {
!self.type_length_limit.value_within_limit(self.printed_type_count)
}
fn print_dyn_existential(
&mut self,
predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@ -2942,7 +2975,7 @@ impl<'tcx> ty::TraitPredicate<'tcx> {
}
}
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)]
pub struct TraitPredPrintWithBoundConstness<'tcx>(
ty::TraitPredicate<'tcx>,
Option<ty::BoundConstness>,

View file

@ -367,7 +367,7 @@ impl<'tcx> TyCtxt<'tcx> {
validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
) -> Option<ty::Destructor> {
let drop_trait = self.lang_items().drop_trait()?;
self.ensure().coherent_trait(drop_trait).ok()?;
self.ensure_ok().coherent_trait(drop_trait).ok()?;
let ty = self.type_of(adt_did).instantiate_identity();
let mut dtor_candidate = None;
@ -404,7 +404,7 @@ impl<'tcx> TyCtxt<'tcx> {
validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
) -> Option<ty::AsyncDestructor> {
let async_drop_trait = self.lang_items().async_drop_trait()?;
self.ensure().coherent_trait(async_drop_trait).ok()?;
self.ensure_ok().coherent_trait(async_drop_trait).ok()?;
let ty = self.type_of(adt_did).instantiate_identity();
let mut dtor_candidate = None;

View file

@ -25,8 +25,6 @@ mir_build_borrow_of_moved_value = borrow of moved value
.occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait
.value_borrowed_label = value borrowed here after move
.suggestion = borrow this binding in the pattern to avoid moving the value
.full_type_name = the full type name has been written to '{$path}'
.consider_verbose = consider using `--verbose` to print the full type name to the console
mir_build_call_to_deprecated_safe_fn_requires_unsafe =
call to deprecated safe function `{$function}` is unsafe and requires unsafe block

View file

@ -47,7 +47,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
/// Create the MIR for a given `DefId`, including unreachable code. Do not call
/// this directly; instead use the cached version via `mir_built`.
pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
tcx.ensure_with_value().thir_abstract_const(def);
tcx.ensure_done().thir_abstract_const(def);
if let Err(e) = tcx.check_match(def) {
return construct_error(tcx, def, e);
}
@ -68,7 +68,7 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
// "not all control paths return a value" is reported here.
//
// maybe move the check to a MIR pass?
tcx.ensure().check_liveness(def);
tcx.ensure_ok().check_liveness(def);
// Don't steal here, instead steal in unsafeck. This is so that
// pattern inline constants can be evaluated as part of building the

View file

@ -200,7 +200,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
fn visit_inner_body(&mut self, def: LocalDefId) {
if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
// Runs all other queries that depend on THIR.
self.tcx.ensure_with_value().mir_built(def);
self.tcx.ensure_done().mir_built(def);
let inner_thir = &inner_thir.steal();
let hir_context = self.tcx.local_def_id_to_hir_id(def);
let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe);
@ -1139,7 +1139,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
let Ok((thir, expr)) = tcx.thir_body(def) else { return };
// Runs all other queries that depend on THIR.
tcx.ensure_with_value().mir_built(def);
tcx.ensure_done().mir_built(def);
let thir = &thir.steal();
let hir_id = tcx.local_def_id_to_hir_id(def);

View file

@ -839,10 +839,6 @@ pub(crate) struct BorrowOfMovedValue {
pub(crate) ty: String,
#[suggestion(code = "ref ", applicability = "machine-applicable")]
pub(crate) suggest_borrowing: Option<Span>,
#[note(mir_build_full_type_name)]
#[note(mir_build_consider_verbose)]
pub(crate) has_path: bool,
pub(crate) path: String,
}
#[derive(Diagnostic)]

View file

@ -797,16 +797,16 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
});
if !conflicts_ref.is_empty() {
let mut path = None;
let ty = cx.tcx.short_ty_string(ty, &mut path);
sess.dcx().emit_err(BorrowOfMovedValue {
let ty = cx.tcx.short_string(ty, &mut path);
let mut err = sess.dcx().create_err(BorrowOfMovedValue {
binding_span: pat.span,
conflicts_ref,
name: Ident::new(name, pat.span),
ty,
suggest_borrowing: Some(pat.span.shrink_to_lo()),
has_path: path.is_some(),
path: path.map(|p| p.display().to_string()).unwrap_or_default(),
});
*err.long_ty_path() = path;
err.emit();
}
return;
}

View file

@ -4,7 +4,7 @@ use std::iter;
use std::ops::{Range, RangeFrom};
use rustc_abi::{ExternAbi, FieldIdx};
use rustc_attr_parsing::InlineAttr;
use rustc_attr_parsing::{InlineAttr, OptimizeAttr};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_index::Idx;
@ -770,6 +770,10 @@ fn check_codegen_attributes<'tcx, I: Inliner<'tcx>>(
return Err("never inline attribute");
}
if let OptimizeAttr::DoNotOptimize = callee_attrs.optimize {
return Err("has DoNotOptimize attribute");
}
// Reachability pass defines which functions are eligible for inlining. Generally inlining
// other functions is incorrect because they could reference symbols that aren't exported.
let is_generic = callsite.callee.args.non_erasable_generics().next().is_some();

View file

@ -421,11 +421,11 @@ fn mir_promoted(
};
// the `has_ffi_unwind_calls` query uses the raw mir, so make sure it is run.
tcx.ensure_with_value().has_ffi_unwind_calls(def);
tcx.ensure_done().has_ffi_unwind_calls(def);
// the `by_move_body` query uses the raw mir, so make sure it is run.
if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) {
tcx.ensure_with_value().coroutine_by_move_body_def_id(def);
tcx.ensure_done().coroutine_by_move_body_def_id(def);
}
let mut body = tcx.mir_built(def).steal();
@ -488,7 +488,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
/// end up missing the source MIR due to stealing happening.
fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
if tcx.is_coroutine(def.to_def_id()) {
tcx.ensure_with_value().mir_coroutine_witnesses(def);
tcx.ensure_done().mir_coroutine_witnesses(def);
}
// We only need to borrowck non-synthetic MIR.
@ -501,7 +501,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
if pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
|| inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id())
{
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
tcx.ensure_done().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
}
}
@ -733,7 +733,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
// Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked`
// which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it
// computes and caches its result.
Some(hir::ConstContext::ConstFn) => tcx.ensure_with_value().mir_for_ctfe(did),
Some(hir::ConstContext::ConstFn) => tcx.ensure_done().mir_for_ctfe(did),
None => {}
Some(other) => panic!("do not use `optimized_mir` for constants: {other:?}"),
}
@ -772,7 +772,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec<Promoted, Body<'_
}
if !tcx.is_synthetic_mir(def) {
tcx.ensure_with_value().mir_borrowck(def);
tcx.ensure_done().mir_borrowck(def);
}
let mut promoted = tcx.mir_promoted(def).1.steal();

View file

@ -1222,7 +1222,7 @@ fn collect_items_of_instance<'tcx>(
mode: CollectionMode,
) -> (MonoItems<'tcx>, MonoItems<'tcx>) {
// This item is getting monomorphized, do mono-time checks.
tcx.ensure().check_mono_item(instance);
tcx.ensure_ok().check_mono_item(instance);
let body = tcx.instance_mir(instance.def);
// Naively, in "used" collection mode, all functions get added to *both* `used_items` and

View file

@ -5,8 +5,8 @@ use std::mem::replace;
use std::num::NonZero;
use rustc_attr_parsing::{
self as attr, AllowedThroughUnstableModules, ConstStability, DeprecatedSince, Stability,
StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER,
self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince,
UnstableReason, VERSION_PLACEHOLDER,
};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
@ -880,7 +880,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
if item_is_allowed {
// The item itself is allowed; check whether the path there is also allowed.
let is_allowed_through_unstable_modules: Option<AllowedThroughUnstableModules> =
let is_allowed_through_unstable_modules: Option<Symbol> =
self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level {
StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
allowed_through_unstable_modules
@ -888,84 +888,80 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
_ => None,
});
if is_allowed_through_unstable_modules.is_none() {
// Check parent modules stability as well if the item the path refers to is itself
// stable. We only emit warnings for unstable path segments if the item is stable
// or allowed because stability is often inherited, so the most common case is that
// both the segments and the item are unstable behind the same feature flag.
//
// We check here rather than in `visit_path_segment` to prevent visiting the last
// path segment twice
//
// We include special cases via #[rustc_allowed_through_unstable_modules] for items
// that were accidentally stabilized through unstable paths before this check was
// added, such as `core::intrinsics::transmute`
let parents = path.segments.iter().rev().skip(1);
for path_segment in parents {
if let Some(def_id) = path_segment.res.opt_def_id() {
// use `None` for id to prevent deprecation check
self.tcx.check_stability_allow_unstable(
def_id,
None,
path.span,
None,
if is_unstable_reexport(self.tcx, id) {
AllowUnstable::Yes
} else {
AllowUnstable::No
},
);
}
}
} else if let Some(AllowedThroughUnstableModules::WithDeprecation(deprecation)) =
is_allowed_through_unstable_modules
{
// Similar to above, but we cannot use `check_stability_allow_unstable` as that would
// immediately show the stability error. We just want to know the result and disaplay
// our own kind of error.
let parents = path.segments.iter().rev().skip(1);
for path_segment in parents {
if let Some(def_id) = path_segment.res.opt_def_id() {
// use `None` for id to prevent deprecation check
let eval_result = self.tcx.eval_stability_allow_unstable(
def_id,
None,
path.span,
None,
if is_unstable_reexport(self.tcx, id) {
AllowUnstable::Yes
} else {
AllowUnstable::No
},
);
let is_allowed = matches!(eval_result, EvalResult::Allow);
if !is_allowed {
// Calculating message for lint involves calling `self.def_path_str`,
// which will by default invoke the expensive `visible_parent_map` query.
// Skip all that work if the lint is allowed anyway.
if self.tcx.lint_level_at_node(DEPRECATED, id).0
== lint::Level::Allow
{
return;
}
// Show a deprecation message.
let def_path =
with_no_trimmed_paths!(self.tcx.def_path_str(def_id));
let def_kind = self.tcx.def_descr(def_id);
let diag = Deprecated {
sub: None,
kind: def_kind.to_owned(),
path: def_path,
note: Some(deprecation),
since_kind: lint::DeprecatedSinceKind::InEffect,
};
self.tcx.emit_node_span_lint(
DEPRECATED,
id,
method_span.unwrap_or(path.span),
diag,
// Check parent modules stability as well if the item the path refers to is itself
// stable. We only emit errors for unstable path segments if the item is stable
// or allowed because stability is often inherited, so the most common case is that
// both the segments and the item are unstable behind the same feature flag.
//
// We check here rather than in `visit_path_segment` to prevent visiting the last
// path segment twice
//
// We include special cases via #[rustc_allowed_through_unstable_modules] for items
// that were accidentally stabilized through unstable paths before this check was
// added, such as `core::intrinsics::transmute`
let parents = path.segments.iter().rev().skip(1);
for path_segment in parents {
if let Some(def_id) = path_segment.res.opt_def_id() {
match is_allowed_through_unstable_modules {
None => {
// Emit a hard stability error if this path is not stable.
// use `None` for id to prevent deprecation check
self.tcx.check_stability_allow_unstable(
def_id,
None,
path.span,
None,
if is_unstable_reexport(self.tcx, id) {
AllowUnstable::Yes
} else {
AllowUnstable::No
},
);
}
Some(deprecation) => {
// Call the stability check directly so that we can control which
// diagnostic is emitted.
let eval_result = self.tcx.eval_stability_allow_unstable(
def_id,
None,
path.span,
None,
if is_unstable_reexport(self.tcx, id) {
AllowUnstable::Yes
} else {
AllowUnstable::No
},
);
let is_allowed = matches!(eval_result, EvalResult::Allow);
if !is_allowed {
// Calculating message for lint involves calling `self.def_path_str`,
// which will by default invoke the expensive `visible_parent_map` query.
// Skip all that work if the lint is allowed anyway.
if self.tcx.lint_level_at_node(DEPRECATED, id).0
== lint::Level::Allow
{
return;
}
// Show a deprecation message.
let def_path =
with_no_trimmed_paths!(self.tcx.def_path_str(def_id));
let def_kind = self.tcx.def_descr(def_id);
let diag = Deprecated {
sub: None,
kind: def_kind.to_owned(),
path: def_path,
note: Some(deprecation),
since_kind: lint::DeprecatedSinceKind::InEffect,
};
self.tcx.emit_node_span_lint(
DEPRECATED,
id,
method_span.unwrap_or(path.span),
diag,
);
}
}
}
}
}

View file

@ -24,7 +24,7 @@ use rustc_ast::MacroDef;
use rustc_ast::visit::{VisitorResult, try_visit};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::intern::Interned;
use rustc_errors::MultiSpan;
use rustc_errors::{MultiSpan, listify};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, InferKind, Visitor};
@ -958,29 +958,15 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
// | ^^ field `gamma` is private # `fields.2` is `false`
// Get the list of all private fields for the main message.
let field_names: Vec<_> = fields.iter().map(|(name, _, _)| name).collect();
let field_names = match &field_names[..] {
[] => return,
[name] => format!("`{name}`"),
[fields @ .., last] => format!(
"{} and `{last}`",
fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
),
};
let Some(field_names) = listify(&fields[..], |(n, _, _)| format!("`{n}`")) else { return };
let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
// Get the list of all private fields when pointing at the `..rest`.
let rest_field_names: Vec<_> =
fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
let rest_len = rest_field_names.len();
let rest_field_names = match &rest_field_names[..] {
[] => String::new(),
[name] => format!("`{name}`"),
[fields @ .., last] => format!(
"{} and `{last}`",
fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
),
};
let rest_field_names =
listify(&rest_field_names[..], |n| format!("`{n}`")).unwrap_or_default();
// Get all the labels for each field or `..rest` in the primary MultiSpan.
let labels = fields
.iter()
@ -1005,7 +991,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
} else {
None
},
field_names: field_names.clone(),
field_names,
variant_descr: def.variant_descr(),
def_path_str: self.tcx.def_path_str(def.did()),
labels,

View file

@ -1819,7 +1819,7 @@ pub fn parse_error_format(
ErrorOutputType::HumanReadable(HumanReadableErrorType::Unicode, color)
}
Some(arg) => {
early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
early_dcx.set_error_format(ErrorOutputType::HumanReadable(
HumanReadableErrorType::Default,
color,
));
@ -2360,7 +2360,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
early_dcx.abort_if_error_and_set_error_format(error_format);
early_dcx.set_error_format(error_format);
let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
early_dcx.early_fatal("`--diagnostic-width` must be an positive integer");
@ -2770,6 +2770,7 @@ pub mod nightly_options {
"the option `{}` is only accepted on the nightly compiler",
opt.name
);
// The non-zero nightly_options_on_stable will force an early_fatal eventually.
let _ = early_dcx.early_err(msg);
}
OptionStability::Stable => {}

View file

@ -277,14 +277,10 @@ impl ParseSess {
) -> Self {
let fallback_bundle = fallback_fluent_bundle(locale_resources, false);
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let emitter = Box::new(HumanEmitter::new(
stderr_destination(ColorConfig::Auto),
Lrc::clone(&fallback_bundle),
));
let fatal_dcx = DiagCtxt::new(emitter);
let fatal_emitter =
Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle));
let dcx = DiagCtxt::new(Box::new(SilentEmitter {
fallback_bundle,
fatal_dcx,
fatal_emitter,
fatal_note: Some(fatal_note),
emit_fatal_diagnostic,
}))
@ -341,8 +337,4 @@ impl ParseSess {
pub fn dcx(&self) -> DiagCtxtHandle<'_> {
self.dcx.handle()
}
pub fn set_dcx(&mut self, dcx: DiagCtxt) {
self.dcx = dcx;
}
}

View file

@ -1362,12 +1362,6 @@ pub struct EarlyDiagCtxt {
dcx: DiagCtxt,
}
impl Default for EarlyDiagCtxt {
fn default() -> Self {
Self::new(ErrorOutputType::default())
}
}
impl EarlyDiagCtxt {
pub fn new(output: ErrorOutputType) -> Self {
let emitter = mk_emitter(output);
@ -1375,10 +1369,9 @@ impl EarlyDiagCtxt {
}
/// Swap out the underlying dcx once we acquire the user's preference on error emission
/// format. Any errors prior to that will cause an abort and all stashed diagnostics of the
/// previous dcx will be emitted.
pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) {
self.dcx.handle().abort_if_errors();
/// format. If `early_err` was previously called this will panic.
pub fn set_error_format(&mut self, output: ErrorOutputType) {
assert!(self.dcx.handle().has_errors().is_none());
let emitter = mk_emitter(output);
self.dcx = DiagCtxt::new(emitter);
@ -1398,7 +1391,7 @@ impl EarlyDiagCtxt {
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
#[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
#[must_use = "raise_fatal must be called on the returned ErrorGuaranteed in order to exit with a non-zero status code"]
pub fn early_err(&self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
self.dcx.handle().err(msg)
}

View file

@ -95,65 +95,32 @@ cfg_match! {
if multibyte_mask == 0 {
assert!(intra_chunk_offset == 0);
// Check if there are any control characters in the chunk. All
// control characters that we can encounter at this point have a
// byte value less than 32 or ...
let control_char_test0 = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(32)) };
let control_char_mask0 = unsafe { _mm_movemask_epi8(control_char_test0) };
// Check for newlines in the chunk
let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) };
let mut newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) };
// ... it's the ASCII 'DEL' character with a value of 127.
let control_char_test1 = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(127)) };
let control_char_mask1 = unsafe { _mm_movemask_epi8(control_char_test1) };
let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1);
let control_char_mask = control_char_mask0 | control_char_mask1;
while newlines_mask != 0 {
let index = newlines_mask.trailing_zeros();
if control_char_mask != 0 {
// Check for newlines in the chunk
let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) };
let newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) };
lines.push(RelativeBytePos(index) + output_offset);
if control_char_mask == newlines_mask {
// All control characters are newlines, record them
let mut newlines_mask = 0xFFFF0000 | newlines_mask as u32;
let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1);
loop {
let index = newlines_mask.trailing_zeros();
if index >= CHUNK_SIZE as u32 {
// We have arrived at the end of the chunk.
break;
}
lines.push(RelativeBytePos(index) + output_offset);
// Clear the bit, so we can find the next one.
newlines_mask &= (!1) << index;
}
// We are done for this chunk. All control characters were
// newlines and we took care of those.
continue;
} else {
// Some of the control characters are not newlines,
// fall through to the slow path below.
}
} else {
// No control characters, nothing to record for this chunk
continue;
// Clear the bit, so we can find the next one.
newlines_mask &= newlines_mask - 1;
}
} else {
// The slow path.
// There are multibyte chars in here, fallback to generic decoding.
let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset;
intra_chunk_offset = analyze_source_file_generic(
&src[scan_start..],
CHUNK_SIZE - intra_chunk_offset,
RelativeBytePos::from_usize(scan_start),
lines,
multi_byte_chars,
);
}
// The slow path.
// There are control chars in here, fallback to generic decoding.
let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset;
intra_chunk_offset = analyze_source_file_generic(
&src[scan_start..],
CHUNK_SIZE - intra_chunk_offset,
RelativeBytePos::from_usize(scan_start),
lines,
multi_byte_chars,
);
}
// There might still be a tail left to analyze
@ -253,65 +220,32 @@ cfg_match! {
if multibyte_mask == 0 {
assert!(intra_chunk_offset == 0);
// Check if there are any control characters in the chunk. All
// control characters that we can encounter at this point have a
// byte value less than 32 or ...
let control_char_test0 = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(32)) };
let control_char_mask0 = unsafe { _mm_movemask_epi8(control_char_test0) };
// Check for newlines in the chunk
let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) };
let mut newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) };
// ... it's the ASCII 'DEL' character with a value of 127.
let control_char_test1 = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(127)) };
let control_char_mask1 = unsafe { _mm_movemask_epi8(control_char_test1) };
let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1);
let control_char_mask = control_char_mask0 | control_char_mask1;
while newlines_mask != 0 {
let index = newlines_mask.trailing_zeros();
if control_char_mask != 0 {
// Check for newlines in the chunk
let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) };
let newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) };
lines.push(RelativeBytePos(index) + output_offset);
if control_char_mask == newlines_mask {
// All control characters are newlines, record them
let mut newlines_mask = 0xFFFF0000 | newlines_mask as u32;
let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1);
loop {
let index = newlines_mask.trailing_zeros();
if index >= CHUNK_SIZE as u32 {
// We have arrived at the end of the chunk.
break;
}
lines.push(RelativeBytePos(index) + output_offset);
// Clear the bit, so we can find the next one.
newlines_mask &= (!1) << index;
}
// We are done for this chunk. All control characters were
// newlines and we took care of those.
continue;
} else {
// Some of the control characters are not newlines,
// fall through to the slow path below.
}
} else {
// No control characters, nothing to record for this chunk
continue;
// Clear the bit, so we can find the next one.
newlines_mask &= newlines_mask - 1;
}
} else {
// The slow path.
// There are multibyte chars in here, fallback to generic decoding.
let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset;
intra_chunk_offset = analyze_source_file_generic(
&src[scan_start..],
CHUNK_SIZE - intra_chunk_offset,
RelativeBytePos::from_usize(scan_start),
lines,
multi_byte_chars,
);
}
// The slow path.
// There are control chars in here, fallback to generic decoding.
let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset;
intra_chunk_offset = analyze_source_file_generic(
&src[scan_start..],
CHUNK_SIZE - intra_chunk_offset,
RelativeBytePos::from_usize(scan_start),
lines,
multi_byte_chars,
);
}
// There might still be a tail left to analyze
@ -369,29 +303,18 @@ fn analyze_source_file_generic(
// string.
let mut char_len = 1;
if byte < 32 {
// This is an ASCII control character, it could be one of the cases
// that are interesting to us.
if byte == b'\n' {
let pos = RelativeBytePos::from_usize(i) + output_offset;
if let b'\n' = byte {
lines.push(pos + RelativeBytePos(1));
}
} else if byte >= 127 {
// The slow path:
// This is either ASCII control character "DEL" or the beginning of
// a multibyte char. Just decode to `char`.
lines.push(pos + RelativeBytePos(1));
} else if byte >= 128 {
// This is the beginning of a multibyte char. Just decode to `char`.
let c = src[i..].chars().next().unwrap();
char_len = c.len_utf8();
let pos = RelativeBytePos::from_usize(i) + output_offset;
if char_len > 1 {
assert!((2..=4).contains(&char_len));
let mbc = MultiByteChar { pos, bytes: char_len as u8 };
multi_byte_chars.push(mbc);
}
assert!((2..=4).contains(&char_len));
let mbc = MultiByteChar { pos, bytes: char_len as u8 };
multi_byte_chars.push(mbc);
}
i += char_len;

View file

@ -600,11 +600,43 @@ impl Span {
!self.is_dummy() && sm.is_span_accessible(self)
}
/// Returns whether `span` originates in a foreign crate's external macro.
///
/// This is used to test whether a lint should not even begin to figure out whether it should
/// be reported on the current node.
pub fn in_external_macro(self, sm: &SourceMap) -> bool {
let expn_data = self.ctxt().outer_expn_data();
match expn_data.kind {
ExpnKind::Root
| ExpnKind::Desugaring(
DesugaringKind::ForLoop
| DesugaringKind::WhileLoop
| DesugaringKind::OpaqueTy
| DesugaringKind::Async
| DesugaringKind::Await,
) => false,
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
ExpnKind::Macro(MacroKind::Bang, _) => {
// Dummy span for the `def_site` means it's an external macro.
expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site)
}
ExpnKind::Macro { .. } => true, // definitely a plugin
}
}
/// Returns `true` if `span` originates in a derive-macro's expansion.
pub fn in_derive_expansion(self) -> bool {
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
}
/// Return whether `span` is generated by `async` or `await`.
pub fn is_from_async_await(self) -> bool {
matches!(
self.ctxt().outer_expn_data().kind,
ExpnKind::Desugaring(DesugaringKind::Async | DesugaringKind::Await),
)
}
/// Gate suggestions that would not be appropriate in a context the user didn't write.
pub fn can_be_used_for_suggestions(self) -> bool {
!self.from_expansion()

View file

@ -314,8 +314,6 @@ symbols! {
Right,
Rust,
RustaceansAreAwesome,
RustcDecodable,
RustcEncodable,
RwLock,
RwLockReadGuard,
RwLockWriteGuard,

View file

@ -435,7 +435,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
terr: TypeError<'tcx>,
param_env: Option<ParamEnv<'tcx>>,
path: &mut Option<PathBuf>,
) {
match *cause.code() {
ObligationCauseCode::Pattern {
@ -458,7 +457,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
format!("this is an iterator with items of type `{}`", args.type_at(0)),
);
} else {
let expected_ty = self.tcx.short_ty_string(expected_ty, path);
let expected_ty = self.tcx.short_string(expected_ty, err.long_ty_path());
err.span_label(span, format!("this expression has type `{expected_ty}`"));
}
}
@ -1545,7 +1544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
(false, Mismatch::Fixed("existential projection"))
}
};
let Some(vals) = self.values_str(values, cause) else {
let Some(vals) = self.values_str(values, cause, diag.long_ty_path()) else {
// Derived error. Cancel the emitter.
// NOTE(eddyb) this was `.cancel()`, but `diag`
// is borrowed, so we can't fully defuse it.
@ -1600,9 +1599,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return;
}
let mut path = None;
if let Some((expected, found, p)) = expected_found {
path = p;
if let Some((expected, found)) = expected_found {
let (expected_label, found_label, exp_found) = match exp_found {
Mismatch::Variable(ef) => (
ef.expected.prefix_string(self.tcx),
@ -1725,32 +1722,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}
TypeError::Sorts(values) => {
let extra = expected == found;
let extra = expected == found
// Ensure that we don't ever say something like
// expected `impl Trait` (opaque type `impl Trait`)
// found `impl Trait` (opaque type `impl Trait`)
&& values.expected.sort_string(self.tcx)
!= values.found.sort_string(self.tcx);
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
(true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
format!(
DiagStyledString::normal(format!(
" (opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
pos.line,
pos.col.to_usize() + 1,
)
))
}
(true, ty::Alias(ty::Projection, proj))
if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
{
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
format!(
DiagStyledString::normal(format!(
" (trait associated opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
pos.line,
pos.col.to_usize() + 1,
)
))
}
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
(false, _) => "".to_string(),
(true, _) => {
let mut s = DiagStyledString::normal(" (");
s.push_highlighted(ty.sort_string(self.tcx));
s.push_normal(")");
s
}
(false, _) => DiagStyledString::normal(""),
};
if !(values.expected.is_simple_text() && values.found.is_simple_text())
|| (exp_found.is_some_and(|ef| {
@ -1767,23 +1774,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}))
{
if let Some(ExpectedFound { found: found_ty, .. }) = exp_found {
if let Some(ExpectedFound { found: found_ty, .. }) = exp_found
&& !self.tcx.ty_is_opaque_future(found_ty)
{
// `Future` is a special opaque type that the compiler
// will try to hide in some case such as `async fn`, so
// to make an error more use friendly we will
// avoid to suggest a mismatch type with a
// type that the user usually are not using
// directly such as `impl Future<Output = u8>`.
if !self.tcx.ty_is_opaque_future(found_ty) {
diag.note_expected_found_extra(
&expected_label,
expected,
&found_label,
found,
&sort_string(values.expected),
&sort_string(values.found),
);
}
diag.note_expected_found_extra(
&expected_label,
expected,
&found_label,
found,
sort_string(values.expected),
sort_string(values.found),
);
}
}
}
@ -1878,11 +1885,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// It reads better to have the error origin as the final
// thing.
self.note_error_origin(diag, cause, exp_found, terr, param_env, &mut path);
if let Some(path) = path {
diag.note(format!("the full type name has been written to '{}'", path.display()));
diag.note("consider using `--verbose` to print the full type name to the console");
}
self.note_error_origin(diag, cause, exp_found, terr, param_env);
debug!(?diag);
}
@ -1891,6 +1894,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&self,
trace: &TypeTrace<'tcx>,
terr: TypeError<'tcx>,
path: &mut Option<PathBuf>,
) -> Vec<TypeErrorAdditionalDiags> {
let mut suggestions = Vec::new();
let span = trace.cause.span;
@ -1969,7 +1973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
})
| ObligationCauseCode::BlockTailExpression(.., source)) = code
&& let hir::MatchSource::TryDesugar(_) = source
&& let Some((expected_ty, found_ty, _)) = self.values_str(trace.values, &trace.cause)
&& let Some((expected_ty, found_ty)) = self.values_str(trace.values, &trace.cause, path)
{
suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert {
found: found_ty.content(),
@ -2048,12 +2052,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
let span = trace.cause.span;
let mut path = None;
let failure_code = trace.cause.as_failure_code_diag(
terr,
span,
self.type_error_additional_suggestions(&trace, terr),
self.type_error_additional_suggestions(&trace, terr, &mut path),
);
let mut diag = self.dcx().create_err(failure_code);
*diag.long_ty_path() = path;
self.note_type_err(
&mut diag,
&trace.cause,
@ -2098,10 +2104,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&self,
values: ValuePairs<'tcx>,
cause: &ObligationCause<'tcx>,
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
file: &mut Option<PathBuf>,
) -> Option<(DiagStyledString, DiagStyledString)> {
match values {
ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found),
ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, file),
ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found),
ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
@ -2111,7 +2118,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
found: exp_found.found.print_trait_sugared(),
};
match self.expected_found_str(pretty_exp_found) {
Some((expected, found, _)) if expected == found => {
Some((expected, found)) if expected == found => {
self.expected_found_str(exp_found)
}
ret => ret,
@ -2133,9 +2140,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
(None, None)
};
let (exp, fnd) =
self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2);
Some((exp, fnd, None))
Some(self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2))
}
}
}
@ -2143,7 +2148,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn expected_found_str_term(
&self,
exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
path: &mut Option<PathBuf>,
) -> Option<(DiagStyledString, DiagStyledString)> {
let exp_found = self.resolve_vars_if_possible(exp_found);
if exp_found.references_error() {
return None;
@ -2158,21 +2164,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let len = self.tcx.sess().diagnostic_width() + 40;
let exp_s = exp.content();
let fnd_s = fnd.content();
let mut path = None;
if exp_s.len() > len {
let exp_s = self.tcx.short_ty_string(expected, &mut path);
let exp_s = self.tcx.short_string(expected, path);
exp = DiagStyledString::highlighted(exp_s);
}
if fnd_s.len() > len {
let fnd_s = self.tcx.short_ty_string(found, &mut path);
let fnd_s = self.tcx.short_string(found, path);
fnd = DiagStyledString::highlighted(fnd_s);
}
(exp, fnd, path)
(exp, fnd)
}
_ => (
DiagStyledString::highlighted(exp_found.expected.to_string()),
DiagStyledString::highlighted(exp_found.found.to_string()),
None,
),
})
}
@ -2181,7 +2185,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn expected_found_str<T: fmt::Display + TypeFoldable<TyCtxt<'tcx>>>(
&self,
exp_found: ty::error::ExpectedFound<T>,
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
) -> Option<(DiagStyledString, DiagStyledString)> {
let exp_found = self.resolve_vars_if_possible(exp_found);
if exp_found.references_error() {
return None;
@ -2190,7 +2194,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
Some((
DiagStyledString::highlighted(exp_found.expected.to_string()),
DiagStyledString::highlighted(exp_found.found.to_string()),
None,
))
}

View file

@ -713,7 +713,7 @@ impl<'tcx> InferSourceKind<'tcx> {
if ty.is_closure() {
("closure", closure_as_fn_str(infcx, ty), path)
} else if !ty.is_ty_or_numeric_infer() {
("normal", infcx.tcx.short_ty_string(ty, &mut path), path)
("normal", infcx.tcx.short_string(ty, &mut path), path)
} else {
("other", String::new(), path)
}

View file

@ -1,422 +0,0 @@
use rustc_errors::{Diag, Subdiagnostic};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, IsSuggestable, Region, Ty};
use rustc_span::kw;
use tracing::debug;
use super::ObligationCauseAsDiagArg;
use crate::error_reporting::infer::{TypeErrCtxt, note_and_explain_region};
use crate::errors::{
FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData,
RegionOriginNote, WhereClauseSuggestions, note_and_explain,
};
use crate::fluent_generated as fluent;
use crate::infer::{self, SubregionOrigin};
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
match *origin {
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
span: trace.cause.span,
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)),
}
.add_to_diag(err),
infer::Reborrow(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err)
}
infer::RelateObjectBound(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
.add_to_diag(err);
}
infer::ReferenceOutlivesReferent(ty, span) => {
RegionOriginNote::WithName {
span,
msg: fluent::infer_reference_outlives_referent,
name: &self.ty_to_string(ty),
continues: false,
}
.add_to_diag(err);
}
infer::RelateParamBound(span, ty, opt_span) => {
RegionOriginNote::WithName {
span,
msg: fluent::infer_relate_param_bound,
name: &self.ty_to_string(ty),
continues: opt_span.is_some(),
}
.add_to_diag(err);
if let Some(span) = opt_span {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
.add_to_diag(err);
}
}
infer::RelateRegionParamBound(span, _) => {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
.add_to_diag(err);
}
infer::CompareImplItemObligation { span, .. } => {
RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
.add_to_diag(err);
}
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
self.note_region_origin(err, parent);
}
infer::AscribeUserTypeProvePredicate(span) => {
RegionOriginNote::Plain {
span,
msg: fluent::infer_ascribe_user_type_prove_predicate,
}
.add_to_diag(err);
}
}
}
pub(super) fn report_concrete_failure(
&self,
generic_param_scope: LocalDefId,
origin: SubregionOrigin<'tcx>,
sub: Region<'tcx>,
sup: Region<'tcx>,
) -> Diag<'a> {
let mut err = match origin {
infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
let mut err = self.report_and_explain_type_error(trace, terr);
match (*sub, *sup) {
(ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
(ty::RePlaceholder(_), _) => {
note_and_explain_region(
self.tcx,
&mut err,
generic_param_scope,
"",
sup,
" doesn't meet the lifetime requirements",
None,
);
}
(_, ty::RePlaceholder(_)) => {
note_and_explain_region(
self.tcx,
&mut err,
generic_param_scope,
"the required lifetime does not necessarily outlive ",
sub,
"",
None,
);
}
_ => {
note_and_explain_region(
self.tcx,
&mut err,
generic_param_scope,
"",
sup,
"...",
None,
);
note_and_explain_region(
self.tcx,
&mut err,
generic_param_scope,
"...does not necessarily outlive ",
sub,
"",
None,
);
}
}
err
}
infer::Reborrow(span) => {
let reference_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::RefValidFor,
note_and_explain::SuffixKind::Continues,
);
let content_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::ContentValidFor,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(OutlivesContent {
span,
notes: reference_valid.into_iter().chain(content_valid).collect(),
})
}
infer::RelateObjectBound(span) => {
let object_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::TypeObjValidFor,
note_and_explain::SuffixKind::Empty,
);
let pointer_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::SourcePointerValidFor,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(OutlivesBound {
span,
notes: object_valid.into_iter().chain(pointer_valid).collect(),
})
}
infer::RelateParamBound(span, ty, opt_span) => {
let prefix = match *sub {
ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
_ => note_and_explain::PrefixKind::TypeOutlive,
};
let suffix = if opt_span.is_some() {
note_and_explain::SuffixKind::ReqByBinding
} else {
note_and_explain::SuffixKind::Empty
};
let note = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
opt_span,
prefix,
suffix,
);
self.dcx().create_err(FulfillReqLifetime {
span,
ty: self.resolve_vars_if_possible(ty),
note,
})
}
infer::RelateRegionParamBound(span, _) => {
let param_instantiated = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::LfParamInstantiatedWith,
note_and_explain::SuffixKind::Empty,
);
let param_must_outlive = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::LfParamMustOutlive,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(LfBoundNotSatisfied {
span,
notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
})
}
infer::ReferenceOutlivesReferent(ty, span) => {
let pointer_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::PointerValidFor,
note_and_explain::SuffixKind::Empty,
);
let data_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::DataValidFor,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(RefLongerThanData {
span,
ty: self.resolve_vars_if_possible(ty),
notes: pointer_valid.into_iter().chain(data_valid).collect(),
})
}
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
let mut err = self.infcx.report_extra_impl_obligation(
span,
impl_item_def_id,
trait_item_def_id,
&format!("`{sup}: {sub}`"),
);
// We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
&& generics.where_clause_span.contains(span)
{
self.suggest_copy_trait_method_bounds(
trait_item_def_id,
impl_item_def_id,
&mut err,
);
}
err
}
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup);
// Don't mention the item name if it's an RPITIT, since that'll just confuse
// folks.
if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) {
let trait_item_span = self.tcx.def_span(trait_item_def_id);
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
err.span_label(
trait_item_span,
format!("definition of `{item_name}` from trait"),
);
}
self.suggest_copy_trait_method_bounds(
trait_item_def_id,
impl_item_def_id,
&mut err,
);
err
}
infer::AscribeUserTypeProvePredicate(span) => {
let instantiated = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sup,
None,
note_and_explain::PrefixKind::LfInstantiatedWith,
note_and_explain::SuffixKind::Empty,
);
let must_outlive = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
sub,
None,
note_and_explain::PrefixKind::LfMustOutlive,
note_and_explain::SuffixKind::Empty,
);
self.dcx().create_err(LfBoundNotSatisfied {
span,
notes: instantiated.into_iter().chain(must_outlive).collect(),
})
}
};
if sub.is_error() || sup.is_error() {
err.downgrade_to_delayed_bug();
}
err
}
pub fn suggest_copy_trait_method_bounds(
&self,
trait_item_def_id: DefId,
impl_item_def_id: LocalDefId,
err: &mut Diag<'_>,
) {
// FIXME(compiler-errors): Right now this is only being used for region
// predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
// but right now it's not really very smart when it comes to implicit `Sized`
// predicates and bounds on the trait itself.
let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx)
else {
return;
};
let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else {
return;
};
let trait_args = trait_ref
.instantiate_identity()
// Replace the explicit self type with `Self` for better suggestion rendering
.with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper))
.args;
let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id)
.rebase_onto(self.tcx, impl_def_id, trait_args);
let Ok(trait_predicates) =
self.tcx
.explicit_predicates_of(trait_item_def_id)
.instantiate_own(self.tcx, trait_item_args)
.map(|(pred, _)| {
if pred.is_suggestable(self.tcx, false) {
Ok(pred.to_string())
} else {
Err(())
}
})
.collect::<Result<Vec<_>, ()>>()
else {
return;
};
let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else {
return;
};
let suggestion = if trait_predicates.is_empty() {
WhereClauseSuggestions::Remove { span: generics.where_clause_span }
} else {
let space = if generics.where_clause_span.is_empty() { " " } else { "" };
WhereClauseSuggestions::CopyPredicates {
span: generics.where_clause_span,
space,
trait_predicates: trait_predicates.join(", "),
}
};
err.subdiagnostic(suggestion);
}
pub(super) fn report_placeholder_failure(
&self,
generic_param_scope: LocalDefId,
placeholder_origin: SubregionOrigin<'tcx>,
sub: Region<'tcx>,
sup: Region<'tcx>,
) -> Diag<'a> {
// I can't think how to do better than this right now. -nikomatsakis
debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
match placeholder_origin {
infer::Subtype(box ref trace)
if matches!(
&trace.cause.code().peel_derives(),
ObligationCauseCode::WhereClause(..)
| ObligationCauseCode::WhereClauseInExpr(..)
) =>
{
// Hack to get around the borrow checker because trace.cause has an `Rc`.
if let ObligationCauseCode::WhereClause(_, span)
| ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
&trace.cause.code().peel_derives()
&& !span.is_dummy()
{
let span = *span;
self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup)
.with_span_note(span, "the lifetime requirement is introduced here")
} else {
unreachable!(
"control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..."
)
}
}
infer::Subtype(box trace) => {
let terr = TypeError::RegionsPlaceholderMismatch;
return self.report_and_explain_type_error(trace, terr);
}
_ => {
return self.report_concrete_failure(
generic_param_scope,
placeholder_origin,
sub,
sup,
);
}
}
}
}

View file

@ -221,7 +221,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
span: trace.cause.span,
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
expected_found: self.values_str(trace.values, &trace.cause).map(|(e, f, _)| (e, f)),
expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()),
}
.add_to_diag(err),
infer::Reborrow(span) => {
@ -946,10 +946,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let infer::Subtype(ref sup_trace) = sup_origin
&& let infer::Subtype(ref sub_trace) = sub_origin
&& let Some((sup_expected, sup_found, _)) =
self.values_str(sup_trace.values, &sup_trace.cause)
&& let Some((sub_expected, sub_found, _)) =
self.values_str(sub_trace.values, &sup_trace.cause)
&& let Some((sup_expected, sup_found)) =
self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path())
&& let Some((sub_expected, sub_found)) =
self.values_str(sub_trace.values, &sup_trace.cause, err.long_ty_path())
&& sub_expected == sup_expected
&& sub_found == sup_found
{

View file

@ -418,7 +418,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
let sugg = match (expected.is_ref(), found.is_ref()) {
(true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
(true, false) => {
FunctionPointerSuggestion::UseRef { span: span.shrink_to_lo() }
}
(false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
(true, true) => {
diag.subdiagnostic(FnItemsAreDistinct);
@ -426,7 +428,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
(false, false) => {
diag.subdiagnostic(FnItemsAreDistinct);
FunctionPointerSuggestion::Cast { span, fn_name, sig }
FunctionPointerSuggestion::Cast { span: span.shrink_to_hi(), sig }
}
};
diag.subdiagnostic(sugg);
@ -466,8 +468,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
} else {
FunctionPointerSuggestion::CastBoth {
span,
fn_name,
span: span.shrink_to_hi(),
found_sig: *found_sig,
expected_sig: *expected_sig,
}

View file

@ -163,6 +163,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let predicate = self.resolve_vars_if_possible(obligation.predicate);
let span = obligation.cause.span;
let mut file = None;
debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
@ -179,7 +180,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return e;
}
if let Err(guar) = self.tcx.ensure().coherent_trait(trait_pred.def_id()) {
if let Err(guar) = self.tcx.ensure_ok().coherent_trait(trait_pred.def_id()) {
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
return guar;
@ -245,7 +246,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
span,
E0283,
"type annotations needed: cannot satisfy `{}`",
predicate,
self.tcx.short_string(predicate, &mut file),
)
};
@ -292,7 +293,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err.cancel();
return e;
}
err.note(format!("cannot satisfy `{predicate}`"));
let pred = self.tcx.short_string(predicate, &mut file);
err.note(format!("cannot satisfy `{pred}`"));
let impl_candidates =
self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
if impl_candidates.len() < 40 {
@ -511,8 +513,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return e;
}
if let Err(guar) =
self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_term.def_id))
if let Err(guar) = self
.tcx
.ensure_ok()
.coherent_trait(self.tcx.parent(data.projection_term.def_id))
{
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
@ -524,6 +528,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
.iter()
.chain(Some(data.term.into_arg()))
.find(|g| g.has_non_region_infer());
let predicate = self.tcx.short_string(predicate, &mut file);
if let Some(arg) = arg {
self.emit_inference_failure_err(
obligation.cause.body_id,
@ -539,8 +544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
self.dcx(),
span,
E0284,
"type annotations needed: cannot satisfy `{}`",
predicate,
"type annotations needed: cannot satisfy `{predicate}`",
)
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
@ -565,12 +569,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err
} else {
// If we can't find a generic parameter, just print a generic error
let predicate = self.tcx.short_string(predicate, &mut file);
struct_span_code_err!(
self.dcx(),
span,
E0284,
"type annotations needed: cannot satisfy `{}`",
predicate,
"type annotations needed: cannot satisfy `{predicate}`",
)
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
@ -590,6 +594,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Some(e) = self.tainted_by_errors() {
return e;
}
let alias = self.tcx.short_string(alias, &mut file);
struct_span_code_err!(
self.dcx(),
span,
@ -603,16 +608,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Some(e) = self.tainted_by_errors() {
return e;
}
let predicate = self.tcx.short_string(predicate, &mut file);
struct_span_code_err!(
self.dcx(),
span,
E0284,
"type annotations needed: cannot satisfy `{}`",
predicate,
"type annotations needed: cannot satisfy `{predicate}`",
)
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
};
*err.long_ty_path() = file;
self.note_obligation_cause(&mut err, obligation);
err.emit()
}

View file

@ -1,5 +1,6 @@
use core::ops::ControlFlow;
use std::borrow::Cow;
use std::path::PathBuf;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::FxHashMap;
@ -9,7 +10,6 @@ use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions,
pluralize, struct_span_code_err,
};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{self as hir, LangItem, Node};
@ -20,8 +20,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{
FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _,
PrintTraitRefExt as _, with_forced_trimmed_paths,
PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, PrintTraitRefExt as _,
with_forced_trimmed_paths,
};
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast};
use rustc_middle::{bug, span_bug};
@ -60,6 +60,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
) -> ErrorGuaranteed {
let tcx = self.tcx;
let mut span = obligation.cause.span;
let mut long_ty_file = None;
let mut err = match *error {
SelectionError::Unimplemented => {
@ -169,11 +170,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Err(guar) = self.fn_arg_obligation(&obligation) {
return guar;
}
let mut file = None;
let (post_message, pre_message, type_def) = self
.get_parent_trait_ref(obligation.cause.code())
.map(|(t, s)| {
let t = self.tcx.short_ty_string(t, &mut file);
let t = self.tcx.short_string(t, &mut long_ty_file);
(
format!(" in `{t}`"),
format!("within `{t}`, "),
@ -181,12 +181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
)
})
.unwrap_or_default();
let file_note = file.as_ref().map(|file| format!(
"the full trait has been written to '{}'",
file.display(),
));
let mut long_ty_file = None;
let OnUnimplementedNote {
message,
@ -223,6 +217,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
None,
append_const_msg,
post_message,
&mut long_ty_file,
);
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)
@ -251,14 +246,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};
let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
*err.long_ty_path() = long_ty_file;
if let Some(long_ty_file) = long_ty_file {
err.note(format!(
"the full name for the type has been written to '{}'",
long_ty_file.display(),
));
err.note("consider using `--verbose` to print the full type name to the console");
}
let mut suggested = false;
if is_try_conversion {
suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
@ -309,7 +298,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return err.emit();
}
file_note.map(|note| err.note(note));
if let Some(s) = label {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
@ -762,14 +750,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_ref: predicate.trait_ref,
polarity: ty::PredicatePolarity::Positive,
});
let mut file = None;
let err_msg = self.get_standard_error_message(
trait_ref,
None,
Some(predicate.constness()),
None,
String::new(),
&mut file,
);
let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
*diag.long_ty_path() = file;
if !self.predicate_may_hold(&Obligation::new(
self.tcx,
ObligationCause::dummy(),
@ -1381,6 +1372,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
_ => (None, error.err),
};
let mut file = None;
let (msg, span, closure_span) = values
.and_then(|(predicate, normalized_term, expected_term)| {
self.maybe_detailed_projection_msg(
@ -1388,24 +1380,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
predicate,
normalized_term,
expected_term,
&mut file,
)
})
.unwrap_or_else(|| {
let mut cx = FmtPrinter::new_with_limit(
self.tcx,
Namespace::TypeNS,
rustc_session::Limit(10),
);
(
with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", {
self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
cx.into_buffer()
})),
with_forced_trimmed_paths!(format!(
"type mismatch resolving `{}`",
self.tcx
.short_string(self.resolve_vars_if_possible(predicate), &mut file),
)),
obligation.cause.span,
None,
)
});
let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}");
*diag.long_ty_path() = file;
if let Some(span) = closure_span {
// Mark the closure decl so that it is seen even if we are pointing at the return
// type or expression.
@ -1471,15 +1461,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
ty.span,
with_forced_trimmed_paths!(Cow::from(format!(
"type mismatch resolving `{}`",
{
let mut cx = FmtPrinter::new_with_limit(
self.tcx,
Namespace::TypeNS,
rustc_session::Limit(5),
);
self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
cx.into_buffer()
}
self.tcx.short_string(
self.resolve_vars_if_possible(predicate),
diag.long_ty_path()
),
))),
true,
)),
@ -1512,13 +1497,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
projection_term: ty::AliasTerm<'tcx>,
normalized_ty: ty::Term<'tcx>,
expected_ty: ty::Term<'tcx>,
file: &mut Option<PathBuf>,
) -> Option<(String, Span, Option<Span>)> {
let trait_def_id = projection_term.trait_def_id(self.tcx);
let self_ty = projection_term.self_ty();
with_forced_trimmed_paths! {
if self.tcx.is_lang_item(projection_term.def_id, LangItem::FnOnceOutput) {
let fn_kind = self_ty.prefix_string(self.tcx);
let (span, closure_span) = if let ty::Closure(def_id, _) = self_ty.kind() {
let def_span = self.tcx.def_span(def_id);
if let Some(local_def_id) = def_id.as_local()
@ -1552,11 +1537,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};
let item = match self_ty.kind() {
ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
_ => self_ty.to_string(),
_ => self.tcx.short_string(self_ty, file),
};
Some((format!(
"expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \
returns `{normalized_ty}`",
"expected `{item}` to return `{expected_ty}`, but it returns `{normalized_ty}`",
), span, closure_span))
} else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) {
Some((format!(
@ -1984,8 +1968,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
StringPart::normal(" implemented for `"),
]);
if types_content.0 == types_content.1 {
let ty =
self.tcx.short_ty_string(obligation_trait_ref.self_ty(), &mut None);
let ty = self
.tcx
.short_string(obligation_trait_ref.self_ty(), err.long_ty_path());
msg.push(StringPart::normal(ty));
} else {
msg.extend(types.0.0);
@ -2342,7 +2327,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// First, attempt to add note to this error with an async-await-specific
// message, and fall back to regular note otherwise.
if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
let mut long_ty_file = None;
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
@ -2351,15 +2335,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
&mut long_ty_file,
);
if let Some(file) = long_ty_file {
err.note(format!(
"the full name for the type has been written to '{}'",
file.display(),
));
err.note("consider using `--verbose` to print the full type name to the console");
}
self.suggest_unsized_bound_if_applicable(err, obligation);
if let Some(span) = err.span.primary_span()
&& let Some(mut diag) =
@ -2403,6 +2379,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
predicate_constness: Option<ty::BoundConstness>,
append_const_msg: Option<AppendConstMessage>,
post_message: String,
long_ty_file: &mut Option<PathBuf>,
) -> String {
message
.and_then(|cannot_do_this| {
@ -2426,7 +2403,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
.unwrap_or_else(|| {
format!(
"the trait bound `{}` is not satisfied{post_message}",
trait_predicate.print_with_bound_constness(predicate_constness)
self.tcx.short_string(
trait_predicate.print_with_bound_constness(predicate_constness),
long_ty_file,
),
)
})
}

View file

@ -306,7 +306,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let ObligationCauseCode::WhereClause(..)
| ObligationCauseCode::WhereClauseInExpr(..) = code
{
let mut long_ty_file = None;
self.note_obligation_cause_code(
error.obligation.cause.body_id,
&mut diag,
@ -315,17 +314,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
code,
&mut vec![],
&mut Default::default(),
&mut long_ty_file,
);
if let Some(file) = long_ty_file {
diag.note(format!(
"the full name for the type has been written to '{}'",
file.display(),
));
diag.note(
"consider using `--verbose` to print the full type name to the console",
);
}
}
diag.emit()
}

View file

@ -932,7 +932,7 @@ impl<'tcx> OnUnimplementedFormatString {
let value = match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
if let Some(ty) = trait_ref.args[param.index as usize].as_type() {
tcx.short_ty_string(ty, long_ty_file)
tcx.short_string(ty, long_ty_file)
} else {
trait_ref.args[param.index as usize].to_string()
}

Some files were not shown because too many files have changed in this diff Show more