mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #116688 - compiler-errors:rustfmt-up, r=WaffleLapkin,Nilstrieb
Format all the let-chains in compiler crates Since rust-lang/rustfmt#5910 has landed, soon we will have support for formatting let-chains (as soon as rustfmt syncs and beta gets bumped). This PR applies the changes [from master rustfmt to rust-lang/rust eagerly](https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/out.20formatting.20of.20prs/near/374997516), so that the next beta bump does not have to deal with a 200+ file diff and can remain concerned with other things like `cfg(bootstrap)` -- #113637 was a pain to land, for example, because of let-else. I will also add this commit to the ignore list after it has landed. The commands that were run -- I'm not great at bash-foo, but this applies rustfmt to every compiler crate, and then reverts the two crates that should probably be formatted out-of-tree. ``` ~/rustfmt $ ls -1d ~/rust/compiler/* | xargs -I@ cargo run --bin rustfmt -- `@/src/lib.rs` --config-path ~/rust --edition=2021 # format all of the compiler crates ~/rust $ git checkout HEAD -- compiler/rustc_codegen_{gcc,cranelift} # revert changes to cg-gcc and cg-clif ``` cc `@rust-lang/rustfmt` r? `@WaffleLapkin` or `@Nilstrieb` who said they may be able to review this purely mechanical PR :> cc `@Mark-Simulacrum` and `@petrochenkov,` who had some thoughts on the order of operations with big formatting changes in https://github.com/rust-lang/rust/pull/95262#issue-1178993801. I think the situation has changed since then, given that let-chains support exists on master rustfmt now, and I'm fairly confident that this formatting PR should land even if *bootstrap* rustfmt doesn't yet format let-chains in order to lessen the burden of the next beta bump.
This commit is contained in:
commit
a48396984a
@ -520,9 +520,7 @@ impl NestedMetaItem {
|
|||||||
I: Iterator<Item = &'a TokenTree>,
|
I: Iterator<Item = &'a TokenTree>,
|
||||||
{
|
{
|
||||||
match tokens.peek() {
|
match tokens.peek() {
|
||||||
Some(TokenTree::Token(token, _))
|
Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
|
||||||
if let Some(lit) = MetaItemLit::from_token(token) =>
|
|
||||||
{
|
|
||||||
tokens.next();
|
tokens.next();
|
||||||
return Some(NestedMetaItem::Lit(lit));
|
return Some(NestedMetaItem::Lit(lit));
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,9 @@ pub fn entry_point_type(
|
|||||||
} else if attr::contains_name(attrs, sym::rustc_main) {
|
} else if attr::contains_name(attrs, sym::rustc_main) {
|
||||||
EntryPointType::RustcMainAttr
|
EntryPointType::RustcMainAttr
|
||||||
} else {
|
} else {
|
||||||
if let Some(name) = name && name == sym::main {
|
if let Some(name) = name
|
||||||
|
&& name == sym::main
|
||||||
|
{
|
||||||
if at_root {
|
if at_root {
|
||||||
// This is a top-level function so it can be `main`.
|
// This is a top-level function so it can be `main`.
|
||||||
EntryPointType::MainNamed
|
EntryPointType::MainNamed
|
||||||
|
@ -107,13 +107,11 @@ impl Lit {
|
|||||||
/// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
|
/// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
|
||||||
pub fn from_token(token: &Token) -> Option<Lit> {
|
pub fn from_token(token: &Token) -> Option<Lit> {
|
||||||
match token.uninterpolate().kind {
|
match token.uninterpolate().kind {
|
||||||
Ident(name, false) if name.is_bool_lit() => {
|
Ident(name, false) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
|
||||||
Some(Lit::new(Bool, name, None))
|
|
||||||
}
|
|
||||||
Literal(token_lit) => Some(token_lit),
|
Literal(token_lit) => Some(token_lit),
|
||||||
Interpolated(ref nt)
|
Interpolated(ref nt)
|
||||||
if let NtExpr(expr) | NtLiteral(expr) = &**nt
|
if let NtExpr(expr) | NtLiteral(expr) = &**nt
|
||||||
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
|
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
|
||||||
{
|
{
|
||||||
Some(token_lit)
|
Some(token_lit)
|
||||||
}
|
}
|
||||||
@ -655,7 +653,9 @@ impl Token {
|
|||||||
|
|
||||||
/// Returns `true` if the token is an interpolated path.
|
/// Returns `true` if the token is an interpolated path.
|
||||||
fn is_path(&self) -> bool {
|
fn is_path(&self) -> bool {
|
||||||
if let Interpolated(nt) = &self.kind && let NtPath(..) = **nt {
|
if let Interpolated(nt) = &self.kind
|
||||||
|
&& let NtPath(..) = **nt
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,7 +677,9 @@ impl Token {
|
|||||||
|
|
||||||
/// Is the token an interpolated block (`$b:block`)?
|
/// Is the token an interpolated block (`$b:block`)?
|
||||||
pub fn is_whole_block(&self) -> bool {
|
pub fn is_whole_block(&self) -> bool {
|
||||||
if let Interpolated(nt) = &self.kind && let NtBlock(..) = **nt {
|
if let Interpolated(nt) = &self.kind
|
||||||
|
&& let NtBlock(..) = **nt
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,7 +550,9 @@ impl TokenStream {
|
|||||||
|
|
||||||
let stream_iter = stream.0.iter().cloned();
|
let stream_iter = stream.0.iter().cloned();
|
||||||
|
|
||||||
if let Some(first) = stream.0.first() && Self::try_glue_to_last(vec_mut, first) {
|
if let Some(first) = stream.0.first()
|
||||||
|
&& Self::try_glue_to_last(vec_mut, first)
|
||||||
|
{
|
||||||
// Now skip the first token tree from `stream`.
|
// Now skip the first token tree from `stream`.
|
||||||
vec_mut.extend(stream_iter.skip(1));
|
vec_mut.extend(stream_iter.skip(1));
|
||||||
} else {
|
} else {
|
||||||
|
@ -673,12 +673,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
|
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
|
||||||
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
|
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
|
||||||
{
|
{
|
||||||
let unstable_span =
|
let unstable_span = self.mark_span_with_reason(
|
||||||
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
|
DesugaringKind::Async,
|
||||||
|
span,
|
||||||
|
self.allow_gen_future.clone(),
|
||||||
|
);
|
||||||
self.lower_attrs(
|
self.lower_attrs(
|
||||||
inner_hir_id,
|
inner_hir_id,
|
||||||
&[Attribute {
|
&[Attribute {
|
||||||
kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(sym::track_caller, span)))),
|
kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(
|
||||||
|
sym::track_caller,
|
||||||
|
span,
|
||||||
|
)))),
|
||||||
id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(),
|
id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(),
|
||||||
style: AttrStyle::Outer,
|
style: AttrStyle::Outer,
|
||||||
span: unstable_span,
|
span: unstable_span,
|
||||||
@ -1102,7 +1108,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
if let ExprKind::Path(qself, path) = &expr.kind {
|
if let ExprKind::Path(qself, path) = &expr.kind {
|
||||||
// Does the path resolve to something disallowed in a tuple struct/variant pattern?
|
// Does the path resolve to something disallowed in a tuple struct/variant pattern?
|
||||||
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||||
if let Some(res) = partial_res.full_res() && !res.expected_in_tuple_struct_pat() {
|
if let Some(res) = partial_res.full_res()
|
||||||
|
&& !res.expected_in_tuple_struct_pat()
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1122,7 +1130,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
if let ExprKind::Path(qself, path) = &expr.kind {
|
if let ExprKind::Path(qself, path) = &expr.kind {
|
||||||
// Does the path resolve to something disallowed in a unit struct/variant pattern?
|
// Does the path resolve to something disallowed in a unit struct/variant pattern?
|
||||||
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||||
if let Some(res) = partial_res.full_res() && !res.expected_in_unit_struct_pat() {
|
if let Some(res) = partial_res.full_res()
|
||||||
|
&& !res.expected_in_unit_struct_pat()
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,12 @@ fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
|
|||||||
let remaining_args = args.split_off(arg_index + 1);
|
let remaining_args = args.split_off(arg_index + 1);
|
||||||
let old_arg_offset = args.len();
|
let old_arg_offset = args.len();
|
||||||
let mut fmt2 = &mut args.pop().unwrap().expr; // The inner FormatArgs.
|
let mut fmt2 = &mut args.pop().unwrap().expr; // The inner FormatArgs.
|
||||||
let fmt2 = loop { // Unwrap the Expr to get to the FormatArgs.
|
let fmt2 = loop {
|
||||||
|
// Unwrap the Expr to get to the FormatArgs.
|
||||||
match &mut fmt2.kind {
|
match &mut fmt2.kind {
|
||||||
ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) => fmt2 = inner,
|
ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) => {
|
||||||
|
fmt2 = inner
|
||||||
|
}
|
||||||
ExprKind::FormatArgs(fmt2) => break fmt2,
|
ExprKind::FormatArgs(fmt2) => break fmt2,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -1387,10 +1387,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
// Desugar `~const` bound in generics into an additional `const host: bool` param
|
// Desugar `~const` bound in generics into an additional `const host: bool` param
|
||||||
// if the effects feature is enabled. This needs to be done before we lower where
|
// if the effects feature is enabled. This needs to be done before we lower where
|
||||||
// clauses since where clauses need to bind to the DefId of the host param
|
// clauses since where clauses need to bind to the DefId of the host param
|
||||||
let host_param_parts = if let Const::Yes(span) = constness && self.tcx.features().effects {
|
let host_param_parts = if let Const::Yes(span) = constness
|
||||||
if let Some(param) = generics.params.iter().find(|x| {
|
&& self.tcx.features().effects
|
||||||
x.attrs.iter().any(|x| x.has_name(sym::rustc_host))
|
{
|
||||||
}) {
|
if let Some(param) =
|
||||||
|
generics.params.iter().find(|x| x.attrs.iter().any(|x| x.has_name(sym::rustc_host)))
|
||||||
|
{
|
||||||
// user has manually specified a `rustc_host` param, in this case, we set
|
// user has manually specified a `rustc_host` param, in this case, we set
|
||||||
// the param id so that lowering logic can use that. But we don't create
|
// the param id so that lowering logic can use that. But we don't create
|
||||||
// another host param, so this gives `None`.
|
// another host param, so this gives `None`.
|
||||||
@ -1399,7 +1401,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
} else {
|
} else {
|
||||||
let param_node_id = self.next_node_id();
|
let param_node_id = self.next_node_id();
|
||||||
let hir_id = self.next_id();
|
let hir_id = self.next_id();
|
||||||
let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
|
let def_id = self.create_def(
|
||||||
|
self.local_def_id(parent_node_id),
|
||||||
|
param_node_id,
|
||||||
|
DefPathData::TypeNs(sym::host),
|
||||||
|
span,
|
||||||
|
);
|
||||||
self.host_param_id = Some(def_id);
|
self.host_param_id = Some(def_id);
|
||||||
Some((span, hir_id, def_id))
|
Some((span, hir_id, def_id))
|
||||||
}
|
}
|
||||||
|
@ -1256,7 +1256,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
&PolyTraitRef {
|
&PolyTraitRef {
|
||||||
bound_generic_params: ThinVec::new(),
|
bound_generic_params: ThinVec::new(),
|
||||||
trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
|
trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
|
||||||
span: t.span
|
span: t.span,
|
||||||
},
|
},
|
||||||
itctx,
|
itctx,
|
||||||
ast::Const::No,
|
ast::Const::No,
|
||||||
|
@ -82,7 +82,8 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
|
|||||||
// We can sometimes encounter bare trait objects
|
// We can sometimes encounter bare trait objects
|
||||||
// which are represented in AST as paths.
|
// which are represented in AST as paths.
|
||||||
if let Some(partial_res) = self.resolver.get_partial_res(t.id)
|
if let Some(partial_res) = self.resolver.get_partial_res(t.id)
|
||||||
&& let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
|
&& let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) =
|
||||||
|
partial_res.full_res()
|
||||||
{
|
{
|
||||||
self.current_binders.push(t.id);
|
self.current_binders.push(t.id);
|
||||||
visit::walk_ty(self, t);
|
visit::walk_ty(self, t);
|
||||||
|
@ -215,14 +215,15 @@ impl<'a> AstValidator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
|
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
|
||||||
if let Some(ident) = field.ident &&
|
if let Some(ident) = field.ident
|
||||||
ident.name == kw::Underscore {
|
&& ident.name == kw::Underscore
|
||||||
self.check_unnamed_field_ty(&field.ty, ident.span);
|
{
|
||||||
self.visit_vis(&field.vis);
|
self.check_unnamed_field_ty(&field.ty, ident.span);
|
||||||
self.visit_ident(ident);
|
self.visit_vis(&field.vis);
|
||||||
self.visit_ty_common(&field.ty);
|
self.visit_ident(ident);
|
||||||
self.walk_ty(&field.ty);
|
self.visit_ty_common(&field.ty);
|
||||||
walk_list!(self, visit_attribute, &field.attrs);
|
self.walk_ty(&field.ty);
|
||||||
|
walk_list!(self, visit_attribute, &field.attrs);
|
||||||
} else {
|
} else {
|
||||||
self.visit_field_def(field);
|
self.visit_field_def(field);
|
||||||
}
|
}
|
||||||
@ -291,13 +292,11 @@ impl<'a> AstValidator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deny_unnamed_field(&self, field: &FieldDef) {
|
fn deny_unnamed_field(&self, field: &FieldDef) {
|
||||||
if let Some(ident) = field.ident &&
|
if let Some(ident) = field.ident
|
||||||
ident.name == kw::Underscore {
|
&& ident.name == kw::Underscore
|
||||||
self.err_handler()
|
{
|
||||||
.emit_err(errors::InvalidUnnamedField {
|
self.err_handler()
|
||||||
span: field.span,
|
.emit_err(errors::InvalidUnnamedField { span: field.span, ident_span: ident.span });
|
||||||
ident_span: ident.span
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1180,28 +1179,40 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||||||
(BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
|
(BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
|
||||||
self.err_handler().emit_err(errors::OptionalTraitSupertrait {
|
self.err_handler().emit_err(errors::OptionalTraitSupertrait {
|
||||||
span: poly.span,
|
span: poly.span,
|
||||||
path_str: pprust::path_to_string(&poly.trait_ref.path)
|
path_str: pprust::path_to_string(&poly.trait_ref.path),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
|
(BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
|
||||||
self.err_handler().emit_err(errors::OptionalTraitObject {span: poly.span});
|
self.err_handler().emit_err(errors::OptionalTraitObject { span: poly.span });
|
||||||
}
|
}
|
||||||
(_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
|
(_, TraitBoundModifier::MaybeConst)
|
||||||
|
if let Some(reason) = &self.disallow_tilde_const =>
|
||||||
|
{
|
||||||
let reason = match reason {
|
let reason = match reason {
|
||||||
DisallowTildeConstContext::TraitObject => errors::TildeConstReason::TraitObject,
|
DisallowTildeConstContext::TraitObject => {
|
||||||
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => errors::TildeConstReason::Closure,
|
errors::TildeConstReason::TraitObject
|
||||||
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => errors::TildeConstReason::Function { ident: ident.span },
|
}
|
||||||
|
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
|
||||||
|
errors::TildeConstReason::Closure
|
||||||
|
}
|
||||||
|
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
|
||||||
|
errors::TildeConstReason::Function { ident: ident.span }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.err_handler().emit_err(errors::TildeConstDisallowed {
|
self.err_handler()
|
||||||
span: bound.span(),
|
.emit_err(errors::TildeConstDisallowed { span: bound.span(), reason });
|
||||||
reason
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
(_, TraitBoundModifier::MaybeConstMaybe) => {
|
(_, TraitBoundModifier::MaybeConstMaybe) => {
|
||||||
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "?" });
|
self.err_handler().emit_err(errors::OptionalConstExclusive {
|
||||||
|
span: bound.span(),
|
||||||
|
modifier: "?",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
(_, TraitBoundModifier::MaybeConstNegative) => {
|
(_, TraitBoundModifier::MaybeConstNegative) => {
|
||||||
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "!" });
|
self.err_handler().emit_err(errors::OptionalConstExclusive {
|
||||||
|
span: bound.span(),
|
||||||
|
modifier: "!",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -1214,7 +1225,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||||||
{
|
{
|
||||||
for arg in &args.args {
|
for arg in &args.args {
|
||||||
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
|
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
|
||||||
self.err_handler().emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
|
self.err_handler()
|
||||||
|
.emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,7 +405,9 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
|
if let Some(s) = since
|
||||||
|
&& s.as_str() == VERSION_PLACEHOLDER
|
||||||
|
{
|
||||||
since = Some(rust_version_symbol());
|
since = Some(rust_version_symbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,13 +696,16 @@ pub fn eval_condition(
|
|||||||
!eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
|
!eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
|
||||||
}
|
}
|
||||||
sym::target => {
|
sym::target => {
|
||||||
if let Some(features) = features && !features.cfg_target_compact {
|
if let Some(features) = features
|
||||||
|
&& !features.cfg_target_compact
|
||||||
|
{
|
||||||
feature_err(
|
feature_err(
|
||||||
sess,
|
sess,
|
||||||
sym::cfg_target_compact,
|
sym::cfg_target_compact,
|
||||||
cfg.span,
|
cfg.span,
|
||||||
"compact `cfg(target(..))` is experimental and subject to change"
|
"compact `cfg(target(..))` is experimental and subject to change",
|
||||||
).emit();
|
)
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
mis.iter().fold(true, |res, mi| {
|
mis.iter().fold(true, |res, mi| {
|
||||||
|
@ -351,7 +351,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
// Check if we are in a situation of `ident @ ident` where we want to suggest
|
// Check if we are in a situation of `ident @ ident` where we want to suggest
|
||||||
// `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.
|
// `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.
|
||||||
if let Some(subpat) = sub && self.pat.is_none() {
|
if let Some(subpat) = sub
|
||||||
|
&& self.pat.is_none()
|
||||||
|
{
|
||||||
self.visit_pat(subpat);
|
self.visit_pat(subpat);
|
||||||
if self.pat.is_some() {
|
if self.pat.is_some() {
|
||||||
self.parent_pat = Some(p);
|
self.parent_pat = Some(p);
|
||||||
@ -370,7 +372,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
let mut finder =
|
let mut finder =
|
||||||
ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None };
|
ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None };
|
||||||
finder.visit_expr(expr);
|
finder.visit_expr(expr);
|
||||||
if let Some(span) = span && let Some(expr) = finder.expr {
|
if let Some(span) = span
|
||||||
|
&& let Some(expr) = finder.expr
|
||||||
|
{
|
||||||
for (_, expr) in hir.parent_iter(expr.hir_id) {
|
for (_, expr) in hir.parent_iter(expr.hir_id) {
|
||||||
if let hir::Node::Expr(expr) = expr {
|
if let hir::Node::Expr(expr) = expr {
|
||||||
if expr.span.contains(span) {
|
if expr.span.contains(span) {
|
||||||
@ -425,10 +429,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
Some(hir::intravisit::FnKind::Method(..)) => "method",
|
Some(hir::intravisit::FnKind::Method(..)) => "method",
|
||||||
Some(hir::intravisit::FnKind::Closure) => "closure",
|
Some(hir::intravisit::FnKind::Closure) => "closure",
|
||||||
};
|
};
|
||||||
span.push_span_label(
|
span.push_span_label(ident.span, format!("in this {descr}"));
|
||||||
ident.span,
|
|
||||||
format!("in this {descr}"),
|
|
||||||
);
|
|
||||||
err.span_note(
|
err.span_note(
|
||||||
span,
|
span,
|
||||||
format!(
|
format!(
|
||||||
@ -441,15 +442,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||||
if let hir::Node::Expr(parent_expr) = parent
|
if let hir::Node::Expr(parent_expr) = parent
|
||||||
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
|
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
|
||||||
&& let hir::ExprKind::Path(
|
&& let hir::ExprKind::Path(hir::QPath::LangItem(
|
||||||
hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _)
|
LangItem::IntoIterIntoIter,
|
||||||
) = call_expr.kind
|
_,
|
||||||
|
_,
|
||||||
|
)) = call_expr.kind
|
||||||
{
|
{
|
||||||
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
|
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
|
||||||
} else if let UseSpans::FnSelfUse {
|
} else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } =
|
||||||
kind: CallKind::Normal { .. },
|
move_spans
|
||||||
..
|
{
|
||||||
} = move_spans {
|
|
||||||
// We already suggest cloning for these cases in `explain_captures`.
|
// We already suggest cloning for these cases in `explain_captures`.
|
||||||
} else {
|
} else {
|
||||||
self.suggest_cloning(err, ty, expr, move_span);
|
self.suggest_cloning(err, ty, expr, move_span);
|
||||||
@ -602,10 +604,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
if self.sugg_span.is_some() {
|
if self.sugg_span.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let hir::StmtKind::Local(hir::Local {
|
if let hir::StmtKind::Local(hir::Local { span, ty, init: None, .. }) = &ex.kind
|
||||||
span, ty, init: None, ..
|
&& span.contains(self.decl_span)
|
||||||
}) = &ex.kind && span.contains(self.decl_span) {
|
{
|
||||||
self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
|
self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
|
||||||
}
|
}
|
||||||
hir::intravisit::walk_stmt(self, ex);
|
hir::intravisit::walk_stmt(self, ex);
|
||||||
}
|
}
|
||||||
@ -743,19 +745,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
".clone()".to_owned()
|
".clone()".to_owned()
|
||||||
};
|
};
|
||||||
if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
|
if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
|
||||||
&& self.infcx
|
&& self
|
||||||
.type_implements_trait(
|
.infcx
|
||||||
clone_trait_def,
|
.type_implements_trait(clone_trait_def, [ty], self.param_env)
|
||||||
[ty],
|
|
||||||
self.param_env,
|
|
||||||
)
|
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
{
|
{
|
||||||
let msg = if let ty::Adt(def, _) = ty.kind()
|
let msg = if let ty::Adt(def, _) = ty.kind()
|
||||||
&& [
|
&& [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)]
|
||||||
tcx.get_diagnostic_item(sym::Arc),
|
.contains(&Some(def.did()))
|
||||||
tcx.get_diagnostic_item(sym::Rc),
|
|
||||||
].contains(&Some(def.did()))
|
|
||||||
{
|
{
|
||||||
"clone the value to increment its reference count"
|
"clone the value to increment its reference count"
|
||||||
} else {
|
} else {
|
||||||
@ -1350,9 +1347,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
// };
|
// };
|
||||||
// corresponding to the desugaring of a for loop `for <pat> in <head> { <body> }`.
|
// corresponding to the desugaring of a for loop `for <pat> in <head> { <body> }`.
|
||||||
if let hir::ExprKind::Call(path, [arg]) = ex.kind
|
if let hir::ExprKind::Call(path, [arg]) = ex.kind
|
||||||
&& let hir::ExprKind::Path(
|
&& let hir::ExprKind::Path(hir::QPath::LangItem(
|
||||||
hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _),
|
LangItem::IntoIterIntoIter,
|
||||||
) = path.kind
|
_,
|
||||||
|
_,
|
||||||
|
)) = path.kind
|
||||||
&& arg.span.contains(self.issue_span)
|
&& arg.span.contains(self.issue_span)
|
||||||
{
|
{
|
||||||
// Find `IntoIterator::into_iter(<head>)`
|
// Find `IntoIterator::into_iter(<head>)`
|
||||||
@ -1370,18 +1369,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
..
|
..
|
||||||
}) = stmt.kind
|
}) = stmt.kind
|
||||||
&& let hir::ExprKind::Call(path, _args) = call.kind
|
&& let hir::ExprKind::Call(path, _args) = call.kind
|
||||||
&& let hir::ExprKind::Path(
|
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _)) =
|
||||||
hir::QPath::LangItem(LangItem::IteratorNext, _, _),
|
path.kind
|
||||||
) = path.kind
|
|
||||||
&& let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind
|
&& let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind
|
||||||
&& let hir::QPath::LangItem(LangItem::OptionSome, pat_span, _) = path
|
&& let hir::QPath::LangItem(LangItem::OptionSome, pat_span, _) = path
|
||||||
&& call.span.contains(self.issue_span)
|
&& call.span.contains(self.issue_span)
|
||||||
{
|
{
|
||||||
// Find `<pat>` and the span for the whole `for` loop.
|
// Find `<pat>` and the span for the whole `for` loop.
|
||||||
if let PatField { pat: hir::Pat {
|
if let PatField {
|
||||||
kind: hir::PatKind::Binding(_, _, ident, ..),
|
pat: hir::Pat { kind: hir::PatKind::Binding(_, _, ident, ..), .. },
|
||||||
..
|
..
|
||||||
}, ..} = field {
|
} = field
|
||||||
|
{
|
||||||
self.loop_bind = Some(ident);
|
self.loop_bind = Some(ident);
|
||||||
}
|
}
|
||||||
self.head_span = Some(*head_span);
|
self.head_span = Some(*head_span);
|
||||||
@ -1441,18 +1440,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
// A bare path doesn't need a `let` assignment, it's already a simple
|
// A bare path doesn't need a `let` assignment, it's already a simple
|
||||||
// binding access.
|
// binding access.
|
||||||
// As a new binding wasn't added, we don't need to modify the advancing call.
|
// As a new binding wasn't added, we don't need to modify the advancing call.
|
||||||
sugg.push((
|
sugg.push((loop_span.with_hi(pat_span.lo()), format!("while let Some(")));
|
||||||
loop_span.with_hi(pat_span.lo()),
|
|
||||||
format!("while let Some("),
|
|
||||||
));
|
|
||||||
sugg.push((
|
sugg.push((
|
||||||
pat_span.shrink_to_hi().with_hi(head.span.lo()),
|
pat_span.shrink_to_hi().with_hi(head.span.lo()),
|
||||||
") = ".to_string(),
|
") = ".to_string(),
|
||||||
));
|
));
|
||||||
sugg.push((
|
sugg.push((head.span.shrink_to_hi(), ".next()".to_string()));
|
||||||
head.span.shrink_to_hi(),
|
|
||||||
".next()".to_string(),
|
|
||||||
));
|
|
||||||
} else {
|
} else {
|
||||||
// Needs a new a `let` binding.
|
// Needs a new a `let` binding.
|
||||||
let indent = if let Some(indent) = sm.indentation_before(loop_span) {
|
let indent = if let Some(indent) = sm.indentation_before(loop_span) {
|
||||||
@ -1483,11 +1476,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
sugg.push((recv.span, "iter".to_string()));
|
sugg.push((recv.span, "iter".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err.multipart_suggestion(
|
err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
|
||||||
msg,
|
|
||||||
sugg,
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
err.help(msg);
|
err.help(msg);
|
||||||
}
|
}
|
||||||
@ -1666,69 +1655,80 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||||
if e.span.contains(self.capture_span) {
|
if e.span.contains(self.capture_span) {
|
||||||
if let hir::ExprKind::Closure(&hir::Closure {
|
if let hir::ExprKind::Closure(&hir::Closure {
|
||||||
movability: None,
|
movability: None,
|
||||||
body,
|
body,
|
||||||
fn_arg_span,
|
fn_arg_span,
|
||||||
fn_decl: hir::FnDecl{ inputs, .. },
|
fn_decl: hir::FnDecl { inputs, .. },
|
||||||
..
|
..
|
||||||
}) = e.kind &&
|
}) = e.kind
|
||||||
let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
|
&& let Some(hir::Node::Expr(body)) = self.hir.find(body.hir_id)
|
||||||
self.suggest_arg = "this: &Self".to_string();
|
{
|
||||||
if inputs.len() > 0 {
|
self.suggest_arg = "this: &Self".to_string();
|
||||||
self.suggest_arg.push_str(", ");
|
if inputs.len() > 0 {
|
||||||
}
|
self.suggest_arg.push_str(", ");
|
||||||
self.in_closure = true;
|
}
|
||||||
self.closure_arg_span = fn_arg_span;
|
self.in_closure = true;
|
||||||
self.visit_expr(body);
|
self.closure_arg_span = fn_arg_span;
|
||||||
self.in_closure = false;
|
self.visit_expr(body);
|
||||||
|
self.in_closure = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
|
if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
|
||||||
if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
|
if let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path
|
||||||
seg.ident.name == kw::SelfLower && self.in_closure {
|
&& seg.ident.name == kw::SelfLower
|
||||||
self.closure_change_spans.push(e.span);
|
&& self.in_closure
|
||||||
|
{
|
||||||
|
self.closure_change_spans.push(e.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::intravisit::walk_expr(self, e);
|
hir::intravisit::walk_expr(self, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
|
fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
|
||||||
if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
|
if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } =
|
||||||
let Some(init) = local.init
|
local.pat
|
||||||
|
&& let Some(init) = local.init
|
||||||
{
|
{
|
||||||
if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
|
if let hir::Expr {
|
||||||
movability: None,
|
kind: hir::ExprKind::Closure(&hir::Closure { movability: None, .. }),
|
||||||
..
|
..
|
||||||
}), .. } = init &&
|
} = init
|
||||||
init.span.contains(self.capture_span) {
|
&& init.span.contains(self.capture_span)
|
||||||
self.closure_local_id = Some(*hir_id);
|
{
|
||||||
|
self.closure_local_id = Some(*hir_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::intravisit::walk_local(self, local);
|
hir::intravisit::walk_local(self, local);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
|
fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
|
||||||
if let hir::StmtKind::Semi(e) = s.kind &&
|
if let hir::StmtKind::Semi(e) = s.kind
|
||||||
let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
|
&& let hir::ExprKind::Call(
|
||||||
let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
|
hir::Expr { kind: hir::ExprKind::Path(path), .. },
|
||||||
let Res::Local(hir_id) = seg.res &&
|
args,
|
||||||
Some(hir_id) == self.closure_local_id {
|
) = e.kind
|
||||||
let (span, arg_str) = if args.len() > 0 {
|
&& let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path
|
||||||
(args[0].span.shrink_to_lo(), "self, ".to_string())
|
&& let Res::Local(hir_id) = seg.res
|
||||||
} else {
|
&& Some(hir_id) == self.closure_local_id
|
||||||
let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
|
{
|
||||||
(span, "(self)".to_string())
|
let (span, arg_str) = if args.len() > 0 {
|
||||||
};
|
(args[0].span.shrink_to_lo(), "self, ".to_string())
|
||||||
self.closure_call_changes.push((span, arg_str));
|
} else {
|
||||||
|
let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
|
||||||
|
(span, "(self)".to_string())
|
||||||
|
};
|
||||||
|
self.closure_call_changes.push((span, arg_str));
|
||||||
}
|
}
|
||||||
hir::intravisit::walk_stmt(self, s);
|
hir::intravisit::walk_stmt(self, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(hir::Node::ImplItem(
|
if let Some(hir::Node::ImplItem(hir::ImplItem {
|
||||||
hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
|
kind: hir::ImplItemKind::Fn(_fn_sig, body_id),
|
||||||
)) = hir.find(self.mir_hir_id()) &&
|
..
|
||||||
let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
|
})) = hir.find(self.mir_hir_id())
|
||||||
|
&& let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
|
||||||
|
{
|
||||||
let mut finder = ExpressionFinder {
|
let mut finder = ExpressionFinder {
|
||||||
capture_span: *capture_kind_span,
|
capture_span: *capture_kind_span,
|
||||||
closure_change_spans: vec![],
|
closure_change_spans: vec![],
|
||||||
@ -2299,15 +2299,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
visitor.visit_stmt(stmt);
|
visitor.visit_stmt(stmt);
|
||||||
|
|
||||||
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
|
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
|
||||||
let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
|
let expr_ty: Option<Ty<'_>> =
|
||||||
|
visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
|
||||||
|
|
||||||
let is_format_arguments_item =
|
let is_format_arguments_item = if let Some(expr_ty) = expr_ty
|
||||||
if let Some(expr_ty) = expr_ty
|
&& let ty::Adt(adt, _) = expr_ty.kind()
|
||||||
&& let ty::Adt(adt, _) = expr_ty.kind() {
|
{
|
||||||
self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did())
|
self.infcx.tcx.lang_items().get(LangItem::FormatArguments)
|
||||||
} else {
|
== Some(adt.did())
|
||||||
false
|
} else {
|
||||||
};
|
false
|
||||||
|
};
|
||||||
|
|
||||||
if visitor.found == 0
|
if visitor.found == 0
|
||||||
&& stmt.span.contains(proper_span)
|
&& stmt.span.contains(proper_span)
|
||||||
|
@ -76,10 +76,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||||||
expr_finder.visit_expr(body.value);
|
expr_finder.visit_expr(body.value);
|
||||||
if let Some(mut expr) = expr_finder.result {
|
if let Some(mut expr) = expr_finder.result {
|
||||||
while let hir::ExprKind::AddrOf(_, _, inner)
|
while let hir::ExprKind::AddrOf(_, _, inner)
|
||||||
| hir::ExprKind::Unary(hir::UnOp::Deref, inner)
|
| hir::ExprKind::Unary(hir::UnOp::Deref, inner)
|
||||||
| hir::ExprKind::Field(inner, _)
|
| hir::ExprKind::Field(inner, _)
|
||||||
| hir::ExprKind::MethodCall(_, inner, _, _)
|
| hir::ExprKind::MethodCall(_, inner, _, _)
|
||||||
| hir::ExprKind::Index(inner, _, _) = &expr.kind
|
| hir::ExprKind::Index(inner, _, _) = &expr.kind
|
||||||
{
|
{
|
||||||
expr = inner;
|
expr = inner;
|
||||||
}
|
}
|
||||||
@ -88,10 +88,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||||||
&& let hir::def::Res::Local(hir_id) = p.res
|
&& let hir::def::Res::Local(hir_id) = p.res
|
||||||
&& let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id)
|
&& let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id)
|
||||||
{
|
{
|
||||||
err.span_label(
|
err.span_label(pat.span, format!("binding `{ident}` declared here"));
|
||||||
pat.span,
|
|
||||||
format!("binding `{ident}` declared here"),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -419,7 +416,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
if self.local_names[local].is_some()
|
if self.local_names[local].is_some()
|
||||||
&& let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place
|
&& let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place
|
||||||
&& let Some(borrowed_local) = place.as_local()
|
&& let Some(borrowed_local) = place.as_local()
|
||||||
&& self.local_names[borrowed_local].is_some() && local != borrowed_local
|
&& self.local_names[borrowed_local].is_some()
|
||||||
|
&& local != borrowed_local
|
||||||
{
|
{
|
||||||
should_note_order = true;
|
should_note_order = true;
|
||||||
}
|
}
|
||||||
|
@ -780,19 +780,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
|
|
||||||
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
|
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
|
||||||
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
|
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
|
||||||
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = **kind
|
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) =
|
||||||
|
**kind
|
||||||
{
|
{
|
||||||
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
|
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
|
||||||
let def_id = def_id.expect_local();
|
let def_id = def_id.expect_local();
|
||||||
if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
|
if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
|
||||||
self.closure_span(def_id, moved_place, places)
|
self.closure_span(def_id, moved_place, places)
|
||||||
{
|
{
|
||||||
return ClosureUse {
|
return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
|
||||||
generator_kind,
|
|
||||||
args_span,
|
|
||||||
capture_kind_span,
|
|
||||||
path_span,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1123,7 +1119,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
&self.infcx.tcx.sess.parse_sess.span_diagnostic,
|
&self.infcx.tcx.sess.parse_sess.span_diagnostic,
|
||||||
CaptureReasonSuggest::FreshReborrow {
|
CaptureReasonSuggest::FreshReborrow {
|
||||||
span: move_span.shrink_to_hi(),
|
span: move_span.shrink_to_hi(),
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if let Some(clone_trait) = tcx.lang_items().clone_trait()
|
if let Some(clone_trait) = tcx.lang_items().clone_trait()
|
||||||
&& let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty])
|
&& let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty])
|
||||||
|
@ -396,17 +396,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
let upvar_hir_id = captured_place.get_root_variable();
|
let upvar_hir_id = captured_place.get_root_variable();
|
||||||
|
|
||||||
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
|
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
|
||||||
&& let hir::PatKind::Binding(
|
&& let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, upvar_ident, _) =
|
||||||
hir::BindingAnnotation::NONE,
|
pat.kind
|
||||||
_,
|
|
||||||
upvar_ident,
|
|
||||||
_,
|
|
||||||
) = pat.kind
|
|
||||||
{
|
{
|
||||||
if upvar_ident.name == kw::SelfLower {
|
if upvar_ident.name == kw::SelfLower {
|
||||||
for (_, node) in self.infcx.tcx.hir().parent_iter(upvar_hir_id) {
|
for (_, node) in self.infcx.tcx.hir().parent_iter(upvar_hir_id) {
|
||||||
if let Some(fn_decl) = node.fn_decl() {
|
if let Some(fn_decl) = node.fn_decl() {
|
||||||
if !matches!(fn_decl.implicit_self, hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef) {
|
if !matches!(
|
||||||
|
fn_decl.implicit_self,
|
||||||
|
hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef
|
||||||
|
) {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
upvar_ident.span,
|
upvar_ident.span,
|
||||||
"consider changing this to be mutable",
|
"consider changing this to be mutable",
|
||||||
@ -573,7 +572,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
self.ty,
|
self.ty,
|
||||||
),
|
),
|
||||||
vec![
|
vec![
|
||||||
vec![ // val.insert(index, rv);
|
vec![
|
||||||
|
// val.insert(index, rv);
|
||||||
(
|
(
|
||||||
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
||||||
".insert(".to_string(),
|
".insert(".to_string(),
|
||||||
@ -584,7 +584,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
),
|
),
|
||||||
(rv.span.shrink_to_hi(), ")".to_string()),
|
(rv.span.shrink_to_hi(), ")".to_string()),
|
||||||
],
|
],
|
||||||
vec![ // val.get_mut(index).map(|v| { *v = rv; });
|
vec![
|
||||||
|
// val.get_mut(index).map(|v| { *v = rv; });
|
||||||
(
|
(
|
||||||
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
||||||
".get_mut(".to_string(),
|
".get_mut(".to_string(),
|
||||||
@ -593,12 +594,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
index.span.shrink_to_hi().with_hi(place.span.hi()),
|
index.span.shrink_to_hi().with_hi(place.span.hi()),
|
||||||
").map(|val| { *val".to_string(),
|
").map(|val| { *val".to_string(),
|
||||||
),
|
),
|
||||||
(
|
(rv.span.shrink_to_hi(), "; })".to_string()),
|
||||||
rv.span.shrink_to_hi(),
|
|
||||||
"; })".to_string(),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
vec![ // let x = val.entry(index).or_insert(rv);
|
vec![
|
||||||
|
// let x = val.entry(index).or_insert(rv);
|
||||||
(val.span.shrink_to_lo(), "let val = ".to_string()),
|
(val.span.shrink_to_lo(), "let val = ".to_string()),
|
||||||
(
|
(
|
||||||
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
||||||
@ -747,10 +746,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
|
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
|
||||||
{
|
{
|
||||||
let body = hir_map.body(body_id);
|
let body = hir_map.body(body_id);
|
||||||
let mut v = BindingFinder {
|
let mut v = BindingFinder { span: pat_span, hir_id: None };
|
||||||
span: pat_span,
|
|
||||||
hir_id: None,
|
|
||||||
};
|
|
||||||
v.visit_body(body);
|
v.visit_body(body);
|
||||||
v.hir_id
|
v.hir_id
|
||||||
} else {
|
} else {
|
||||||
@ -766,7 +762,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||||
..
|
..
|
||||||
})) = hir_map.find(hir_id)
|
})) = hir_map.find(hir_id)
|
||||||
&& let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
|
&& let Ok(name) =
|
||||||
|
self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
|
||||||
{
|
{
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
pat_span,
|
pat_span,
|
||||||
@ -879,12 +876,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
// `span` corresponds to the expression being iterated, find the `for`-loop desugared
|
// `span` corresponds to the expression being iterated, find the `for`-loop desugared
|
||||||
// expression with that span in order to identify potential fixes when encountering a
|
// expression with that span in order to identify potential fixes when encountering a
|
||||||
// read-only iterator that should be mutable.
|
// read-only iterator that should be mutable.
|
||||||
let mut v = Finder {
|
let mut v = Finder { span, expr: None };
|
||||||
span,
|
|
||||||
expr: None,
|
|
||||||
};
|
|
||||||
v.visit_block(block);
|
v.visit_block(block);
|
||||||
if let Some(expr) = v.expr && let Call(_, [expr]) = expr.kind {
|
if let Some(expr) = v.expr
|
||||||
|
&& let Call(_, [expr]) = expr.kind
|
||||||
|
{
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
MethodCall(path_segment, _, _, span) => {
|
MethodCall(path_segment, _, _, span) => {
|
||||||
// We have `for _ in iter.read_only_iter()`, try to
|
// We have `for _ in iter.read_only_iter()`, try to
|
||||||
@ -1032,38 +1028,42 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
let source = self.body.source;
|
let source = self.body.source;
|
||||||
let hir = self.infcx.tcx.hir();
|
let hir = self.infcx.tcx.hir();
|
||||||
if let InstanceDef::Item(def_id) = source.instance
|
if let InstanceDef::Item(def_id) = source.instance
|
||||||
&& let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id)
|
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
|
||||||
&& let ExprKind::Closure(closure) = kind && closure.movability == None
|
&& let ExprKind::Closure(closure) = kind
|
||||||
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) {
|
&& closure.movability == None
|
||||||
let mut cur_expr = expr;
|
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
|
||||||
while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
|
{
|
||||||
if path_segment.ident.name == sym::iter {
|
let mut cur_expr = expr;
|
||||||
// check `_ty` has `iter_mut` method
|
while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
|
||||||
let res = self
|
if path_segment.ident.name == sym::iter {
|
||||||
.infcx
|
// check `_ty` has `iter_mut` method
|
||||||
.tcx
|
let res = self
|
||||||
.typeck(path_segment.hir_id.owner.def_id)
|
.infcx
|
||||||
.type_dependent_def_id(cur_expr.hir_id)
|
.tcx
|
||||||
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
|
.typeck(path_segment.hir_id.owner.def_id)
|
||||||
.map(|def_id| self.infcx.tcx.associated_items(def_id))
|
.type_dependent_def_id(cur_expr.hir_id)
|
||||||
.map(|assoc_items| {
|
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
|
||||||
assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
|
.map(|def_id| self.infcx.tcx.associated_items(def_id))
|
||||||
});
|
.map(|assoc_items| {
|
||||||
|
assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(mut res) = res && res.peek().is_some() {
|
if let Some(mut res) = res
|
||||||
err.span_suggestion_verbose(
|
&& res.peek().is_some()
|
||||||
path_segment.ident.span,
|
{
|
||||||
"you may want to use `iter_mut` here",
|
err.span_suggestion_verbose(
|
||||||
"iter_mut",
|
path_segment.ident.span,
|
||||||
Applicability::MaybeIncorrect,
|
"you may want to use `iter_mut` here",
|
||||||
);
|
"iter_mut",
|
||||||
}
|
Applicability::MaybeIncorrect,
|
||||||
break;
|
);
|
||||||
} else {
|
|
||||||
cur_expr = recv;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
cur_expr = recv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_make_local_mut(
|
fn suggest_make_local_mut(
|
||||||
@ -1200,14 +1200,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
let hir_map = self.infcx.tcx.hir();
|
let hir_map = self.infcx.tcx.hir();
|
||||||
let def_id = self.body.source.def_id();
|
let def_id = self.body.source.def_id();
|
||||||
let hir_id = if let Some(local_def_id) = def_id.as_local() &&
|
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
||||||
let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
|
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
|
||||||
{
|
{
|
||||||
let body = hir_map.body(body_id);
|
let body = hir_map.body(body_id);
|
||||||
let mut v = BindingFinder {
|
let mut v = BindingFinder { span: err_label_span, hir_id: None };
|
||||||
span: err_label_span,
|
|
||||||
hir_id: None,
|
|
||||||
};
|
|
||||||
v.visit_body(body);
|
v.visit_body(body);
|
||||||
v.hir_id
|
v.hir_id
|
||||||
} else {
|
} else {
|
||||||
@ -1215,15 +1212,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(hir_id) = hir_id
|
if let Some(hir_id) = hir_id
|
||||||
&& let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
|
&& let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
|
||||||
{
|
{
|
||||||
let (changing, span, sugg) = match local.ty {
|
let (changing, span, sugg) = match local.ty {
|
||||||
Some(ty) => ("changing", ty.span, message),
|
Some(ty) => ("changing", ty.span, message),
|
||||||
None => (
|
None => {
|
||||||
"specifying",
|
("specifying", local.pat.span.shrink_to_hi(), format!(": {message}"))
|
||||||
local.pat.span.shrink_to_hi(),
|
}
|
||||||
format!(": {message}"),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span,
|
span,
|
||||||
@ -1234,9 +1229,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
err_label_span,
|
err_label_span,
|
||||||
format!(
|
format!("consider changing this binding's type to be: `{message}`"),
|
||||||
"consider changing this binding's type to be: `{message}`"
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1380,11 +1373,7 @@ fn suggest_ampmut<'tcx>(
|
|||||||
let ty_mut = decl_ty.builtin_deref(true).unwrap();
|
let ty_mut = decl_ty.builtin_deref(true).unwrap();
|
||||||
assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
|
assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
|
||||||
|
|
||||||
(
|
(false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty_mut.ty))
|
||||||
false,
|
|
||||||
span,
|
|
||||||
format!("{}mut {}", if decl_ty.is_ref() {"&"} else {"*"}, ty_mut.ty)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -942,9 +942,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||||||
ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
|
ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
tcx.any_free_region_meets(pred, |r| {
|
tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyBound(region))
|
||||||
*r == ty::ReEarlyBound(region)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -173,7 +173,9 @@ fn do_mir_borrowck<'tcx>(
|
|||||||
for var_debug_info in &input_body.var_debug_info {
|
for var_debug_info in &input_body.var_debug_info {
|
||||||
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
|
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
|
||||||
if let Some(local) = place.as_local() {
|
if let Some(local) = place.as_local() {
|
||||||
if let Some(prev_name) = local_names[local] && var_debug_info.name != prev_name {
|
if let Some(prev_name) = local_names[local]
|
||||||
|
&& var_debug_info.name != prev_name
|
||||||
|
{
|
||||||
span_bug!(
|
span_bug!(
|
||||||
var_debug_info.source_info.span,
|
var_debug_info.source_info.span,
|
||||||
"local {:?} has many names (`{}` vs `{}`)",
|
"local {:?} has many names (`{}` vs `{}`)",
|
||||||
|
@ -49,7 +49,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
// If the query has created new universes and errors are going to be emitted, register the
|
// If the query has created new universes and errors are going to be emitted, register the
|
||||||
// cause of these new universes for improved diagnostics.
|
// cause of these new universes for improved diagnostics.
|
||||||
let universe = self.infcx.universe();
|
let universe = self.infcx.universe();
|
||||||
if old_universe != universe && let Some(error_info) = error_info {
|
if old_universe != universe
|
||||||
|
&& let Some(error_info) = error_info
|
||||||
|
{
|
||||||
let universe_info = error_info.to_universe_info(old_universe);
|
let universe_info = error_info.to_universe_info(old_universe);
|
||||||
for u in (old_universe + 1)..=universe {
|
for u in (old_universe + 1)..=universe {
|
||||||
self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
|
self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
|
||||||
|
@ -21,20 +21,22 @@ pub fn expand(
|
|||||||
|
|
||||||
// Allow using `#[alloc_error_handler]` on an item statement
|
// Allow using `#[alloc_error_handler]` on an item statement
|
||||||
// FIXME - if we get deref patterns, use them to reduce duplication here
|
// FIXME - if we get deref patterns, use them to reduce duplication here
|
||||||
let (item, is_stmt, sig_span) =
|
let (item, is_stmt, sig_span) = if let Annotatable::Item(item) = &item
|
||||||
if let Annotatable::Item(item) = &item
|
&& let ItemKind::Fn(fn_kind) = &item.kind
|
||||||
&& let ItemKind::Fn(fn_kind) = &item.kind
|
{
|
||||||
{
|
(item, false, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
||||||
(item, false, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
} else if let Annotatable::Stmt(stmt) = &item
|
||||||
} else if let Annotatable::Stmt(stmt) = &item
|
&& let StmtKind::Item(item) = &stmt.kind
|
||||||
&& let StmtKind::Item(item) = &stmt.kind
|
&& let ItemKind::Fn(fn_kind) = &item.kind
|
||||||
&& let ItemKind::Fn(fn_kind) = &item.kind
|
{
|
||||||
{
|
(item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
||||||
(item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
} else {
|
||||||
} else {
|
ecx.sess
|
||||||
ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() });
|
.parse_sess
|
||||||
return vec![orig_item];
|
.span_diagnostic
|
||||||
};
|
.emit_err(errors::AllocErrorMustBeFn { span: item.span() });
|
||||||
|
return vec![orig_item];
|
||||||
|
};
|
||||||
|
|
||||||
// Generate a bunch of new items using the AllocFnFactory
|
// Generate a bunch of new items using the AllocFnFactory
|
||||||
let span = ecx.with_def_site_ctxt(item.span);
|
let span = ecx.with_def_site_ctxt(item.span);
|
||||||
|
@ -193,10 +193,9 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||||||
fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
|
fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
|
||||||
match &mut expr.kind {
|
match &mut expr.kind {
|
||||||
ExprKind::AddrOf(_, mutability, local_expr) => {
|
ExprKind::AddrOf(_, mutability, local_expr) => {
|
||||||
self.with_is_consumed_management(
|
self.with_is_consumed_management(matches!(mutability, Mutability::Mut), |this| {
|
||||||
matches!(mutability, Mutability::Mut),
|
this.manage_cond_expr(local_expr)
|
||||||
|this| this.manage_cond_expr(local_expr)
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
ExprKind::Array(local_exprs) => {
|
ExprKind::Array(local_exprs) => {
|
||||||
for local_expr in local_exprs {
|
for local_expr in local_exprs {
|
||||||
@ -223,7 +222,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||||||
|this| {
|
|this| {
|
||||||
this.manage_cond_expr(lhs);
|
this.manage_cond_expr(lhs);
|
||||||
this.manage_cond_expr(rhs);
|
this.manage_cond_expr(rhs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ExprKind::Call(_, local_exprs) => {
|
ExprKind::Call(_, local_exprs) => {
|
||||||
@ -285,10 +284,9 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Unary(un_op, local_expr) => {
|
ExprKind::Unary(un_op, local_expr) => {
|
||||||
self.with_is_consumed_management(
|
self.with_is_consumed_management(matches!(un_op, UnOp::Neg | UnOp::Not), |this| {
|
||||||
matches!(un_op, UnOp::Neg | UnOp::Not),
|
this.manage_cond_expr(local_expr)
|
||||||
|this| this.manage_cond_expr(local_expr)
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// Expressions that are not worth or can not be captured.
|
// Expressions that are not worth or can not be captured.
|
||||||
//
|
//
|
||||||
|
@ -33,7 +33,7 @@ pub fn expand_concat(
|
|||||||
accumulator.push_str(&b.to_string());
|
accumulator.push_str(&b.to_string());
|
||||||
}
|
}
|
||||||
Ok(ast::LitKind::CStr(..)) => {
|
Ok(ast::LitKind::CStr(..)) => {
|
||||||
cx.emit_err(errors::ConcatCStrLit{ span: e.span});
|
cx.emit_err(errors::ConcatCStrLit { span: e.span });
|
||||||
has_errors = true;
|
has_errors = true;
|
||||||
}
|
}
|
||||||
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
|
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
|
||||||
@ -49,7 +49,9 @@ pub fn expand_concat(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
// We also want to allow negative numeric literals.
|
// We also want to allow negative numeric literals.
|
||||||
ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) if let ast::ExprKind::Lit(token_lit) = expr.kind => {
|
ast::ExprKind::Unary(ast::UnOp::Neg, ref expr)
|
||||||
|
if let ast::ExprKind::Lit(token_lit) = expr.kind =>
|
||||||
|
{
|
||||||
match ast::LitKind::from_token_lit(token_lit) {
|
match ast::LitKind::from_token_lit(token_lit) {
|
||||||
Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")),
|
Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")),
|
||||||
Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")),
|
Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")),
|
||||||
|
@ -140,8 +140,8 @@ pub fn expand_concat_bytes(
|
|||||||
}
|
}
|
||||||
ast::ExprKind::Repeat(expr, count) => {
|
ast::ExprKind::Repeat(expr, count) => {
|
||||||
if let ast::ExprKind::Lit(token_lit) = count.value.kind
|
if let ast::ExprKind::Lit(token_lit) = count.value.kind
|
||||||
&& let Ok(ast::LitKind::Int(count_val, _)) =
|
&& let Ok(ast::LitKind::Int(count_val, _)) =
|
||||||
ast::LitKind::from_token_lit(token_lit)
|
ast::LitKind::from_token_lit(token_lit)
|
||||||
{
|
{
|
||||||
if let Some(elem) =
|
if let Some(elem) =
|
||||||
handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
|
handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
|
||||||
@ -151,7 +151,7 @@ pub fn expand_concat_bytes(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cx.emit_err(errors::ConcatBytesBadRepeat {span: count.value.span });
|
cx.emit_err(errors::ConcatBytesBadRepeat { span: count.value.span });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
|
&ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
|
||||||
|
@ -106,7 +106,9 @@ fn cs_clone_simple(
|
|||||||
// This basic redundancy checking only prevents duplication of
|
// This basic redundancy checking only prevents duplication of
|
||||||
// assertions like `AssertParamIsClone<Foo>` where the type is a
|
// assertions like `AssertParamIsClone<Foo>` where the type is a
|
||||||
// simple name. That's enough to get a lot of cases, though.
|
// simple name. That's enough to get a lot of cases, though.
|
||||||
if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
|
if let Some(name) = field.ty.kind.is_simple_path()
|
||||||
|
&& !seen_type_names.insert(name)
|
||||||
|
{
|
||||||
// Already produced an assertion for this type.
|
// Already produced an assertion for this type.
|
||||||
} else {
|
} else {
|
||||||
// let _: AssertParamIsClone<FieldTy>;
|
// let _: AssertParamIsClone<FieldTy>;
|
||||||
|
@ -73,7 +73,9 @@ fn cs_total_eq_assert(
|
|||||||
// This basic redundancy checking only prevents duplication of
|
// This basic redundancy checking only prevents duplication of
|
||||||
// assertions like `AssertParamIsEq<Foo>` where the type is a
|
// assertions like `AssertParamIsEq<Foo>` where the type is a
|
||||||
// simple name. That's enough to get a lot of cases, though.
|
// simple name. That's enough to get a lot of cases, though.
|
||||||
if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
|
if let Some(name) = field.ty.kind.is_simple_path()
|
||||||
|
&& !seen_type_names.insert(name)
|
||||||
|
{
|
||||||
// Already produced an assertion for this type.
|
// Already produced an assertion for this type.
|
||||||
} else {
|
} else {
|
||||||
// let _: AssertParamIsEq<FieldTy>;
|
// let _: AssertParamIsEq<FieldTy>;
|
||||||
|
@ -21,25 +21,26 @@ pub fn expand_deriving_partial_ord(
|
|||||||
|
|
||||||
// Order in which to perform matching
|
// Order in which to perform matching
|
||||||
let tag_then_data = if let Annotatable::Item(item) = item
|
let tag_then_data = if let Annotatable::Item(item) = item
|
||||||
&& let ItemKind::Enum(def, _) = &item.kind {
|
&& let ItemKind::Enum(def, _) = &item.kind
|
||||||
let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
|
{
|
||||||
match dataful.iter().filter(|&&b| b).count() {
|
let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
|
||||||
// No data, placing the tag check first makes codegen simpler
|
match dataful.iter().filter(|&&b| b).count() {
|
||||||
0 => true,
|
// No data, placing the tag check first makes codegen simpler
|
||||||
1..=2 => false,
|
0 => true,
|
||||||
_ => {
|
1..=2 => false,
|
||||||
(0..dataful.len()-1).any(|i| {
|
_ => (0..dataful.len() - 1).any(|i| {
|
||||||
if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) {
|
if dataful[i]
|
||||||
idx >= 2
|
&& let Some(idx) = dataful[i + 1..].iter().position(|v| *v)
|
||||||
} else {
|
{
|
||||||
false
|
idx >= 2
|
||||||
}
|
} else {
|
||||||
})
|
false
|
||||||
}
|
}
|
||||||
}
|
}),
|
||||||
} else {
|
}
|
||||||
true
|
} else {
|
||||||
};
|
true
|
||||||
|
};
|
||||||
let partial_cmp_def = MethodDef {
|
let partial_cmp_def = MethodDef {
|
||||||
name: sym::partial_cmp,
|
name: sym::partial_cmp,
|
||||||
generics: Bounds::empty(),
|
generics: Bounds::empty(),
|
||||||
@ -133,12 +134,16 @@ fn cs_partial_cmp(
|
|||||||
if !tag_then_data
|
if !tag_then_data
|
||||||
&& let ExprKind::Match(_, arms) = &mut expr1.kind
|
&& let ExprKind::Match(_, arms) = &mut expr1.kind
|
||||||
&& let Some(last) = arms.last_mut()
|
&& let Some(last) = arms.last_mut()
|
||||||
&& let PatKind::Wild = last.pat.kind {
|
&& let PatKind::Wild = last.pat.kind
|
||||||
last.body = expr2;
|
{
|
||||||
expr1
|
last.body = expr2;
|
||||||
|
expr1
|
||||||
} else {
|
} else {
|
||||||
let eq_arm =
|
let eq_arm = cx.arm(
|
||||||
cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
|
span,
|
||||||
|
cx.pat_some(span, cx.pat_path(span, equal_path.clone())),
|
||||||
|
expr1,
|
||||||
|
);
|
||||||
let neq_arm =
|
let neq_arm =
|
||||||
cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
|
cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
|
||||||
cx.expr_match(span, expr2, thin_vec![eq_arm, neq_arm])
|
cx.expr_match(span, expr2, thin_vec![eq_arm, neq_arm])
|
||||||
|
@ -73,7 +73,9 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
|||||||
|
|
||||||
let first_token = &p.token;
|
let first_token = &p.token;
|
||||||
|
|
||||||
let fmtstr = if let token::Literal(lit) = first_token.kind && matches!(lit.kind, token::Str | token::StrRaw(_)) {
|
let fmtstr = if let token::Literal(lit) = first_token.kind
|
||||||
|
&& matches!(lit.kind, token::Str | token::StrRaw(_))
|
||||||
|
{
|
||||||
// This allows us to properly handle cases when the first comma
|
// This allows us to properly handle cases when the first comma
|
||||||
// after the format string is mistakenly replaced with any operator,
|
// after the format string is mistakenly replaced with any operator,
|
||||||
// which cause the expression parser to eat too much tokens.
|
// which cause the expression parser to eat too much tokens.
|
||||||
@ -176,7 +178,7 @@ fn make_format_args(
|
|||||||
&& block.stmts.len() == 1
|
&& block.stmts.len() == 1
|
||||||
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
||||||
&& let ExprKind::Path(None, path) = &expr.kind
|
&& let ExprKind::Path(None, path) = &expr.kind
|
||||||
&& path.is_potential_trivial_const_arg()
|
&& path.is_potential_trivial_const_arg()
|
||||||
{
|
{
|
||||||
err.multipart_suggestion(
|
err.multipart_suggestion(
|
||||||
"quote your inlined format argument to use as string literal",
|
"quote your inlined format argument to use as string literal",
|
||||||
@ -184,7 +186,7 @@ fn make_format_args(
|
|||||||
(unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
|
(unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
|
||||||
(unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
|
(unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
|
||||||
],
|
],
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let sugg_fmt = match args.explicit_args().len() {
|
let sugg_fmt = match args.explicit_args().len() {
|
||||||
@ -257,8 +259,13 @@ fn make_format_args(
|
|||||||
if let Some(note) = err.note {
|
if let Some(note) = err.note {
|
||||||
e.note_ = Some(errors::InvalidFormatStringNote { note });
|
e.note_ = Some(errors::InvalidFormatStringNote { note });
|
||||||
}
|
}
|
||||||
if let Some((label, span)) = err.secondary_label && is_source_literal {
|
if let Some((label, span)) = err.secondary_label
|
||||||
e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } );
|
&& is_source_literal
|
||||||
|
{
|
||||||
|
e.label_ = Some(errors::InvalidFormatStringLabel {
|
||||||
|
span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)),
|
||||||
|
label,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
match err.suggestion {
|
match err.suggestion {
|
||||||
parse::Suggestion::None => {}
|
parse::Suggestion::None => {}
|
||||||
|
@ -24,20 +24,22 @@ pub fn expand(
|
|||||||
|
|
||||||
// Allow using `#[global_allocator]` on an item statement
|
// Allow using `#[global_allocator]` on an item statement
|
||||||
// FIXME - if we get deref patterns, use them to reduce duplication here
|
// FIXME - if we get deref patterns, use them to reduce duplication here
|
||||||
let (item, is_stmt, ty_span) =
|
let (item, is_stmt, ty_span) = if let Annotatable::Item(item) = &item
|
||||||
if let Annotatable::Item(item) = &item
|
&& let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind
|
||||||
&& let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind
|
{
|
||||||
{
|
(item, false, ecx.with_def_site_ctxt(ty.span))
|
||||||
(item, false, ecx.with_def_site_ctxt(ty.span))
|
} else if let Annotatable::Stmt(stmt) = &item
|
||||||
} else if let Annotatable::Stmt(stmt) = &item
|
&& let StmtKind::Item(item) = &stmt.kind
|
||||||
&& let StmtKind::Item(item) = &stmt.kind
|
&& let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind
|
||||||
&& let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind
|
{
|
||||||
{
|
(item, true, ecx.with_def_site_ctxt(ty.span))
|
||||||
(item, true, ecx.with_def_site_ctxt(ty.span))
|
} else {
|
||||||
} else {
|
ecx.sess
|
||||||
ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocMustStatics{span: item.span()});
|
.parse_sess
|
||||||
return vec![orig_item];
|
.span_diagnostic
|
||||||
};
|
.emit_err(errors::AllocMustStatics { span: item.span() });
|
||||||
|
return vec![orig_item];
|
||||||
|
};
|
||||||
|
|
||||||
// Generate a bunch of new items using the AllocFnFactory
|
// Generate a bunch of new items using the AllocFnFactory
|
||||||
let span = ecx.with_def_site_ctxt(item.span);
|
let span = ecx.with_def_site_ctxt(item.span);
|
||||||
|
@ -35,11 +35,13 @@ pub fn expand_test_case(
|
|||||||
let sp = ecx.with_def_site_ctxt(attr_sp);
|
let sp = ecx.with_def_site_ctxt(attr_sp);
|
||||||
let (mut item, is_stmt) = match anno_item {
|
let (mut item, is_stmt) = match anno_item {
|
||||||
Annotatable::Item(item) => (item, false),
|
Annotatable::Item(item) => (item, false),
|
||||||
Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
|
Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => {
|
||||||
(i, true)
|
if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
|
||||||
} else {
|
(i, true)
|
||||||
unreachable!()
|
} else {
|
||||||
},
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() });
|
ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() });
|
||||||
return vec![];
|
return vec![];
|
||||||
|
@ -1521,8 +1521,13 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||||||
llfn: &'ll Value,
|
llfn: &'ll Value,
|
||||||
) {
|
) {
|
||||||
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
|
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
|
||||||
if self.tcx.sess.is_sanitizer_cfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
|
if self.tcx.sess.is_sanitizer_cfi_enabled()
|
||||||
if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::CFI) {
|
&& let Some(fn_abi) = fn_abi
|
||||||
|
&& is_indirect_call
|
||||||
|
{
|
||||||
|
if let Some(fn_attrs) = fn_attrs
|
||||||
|
&& fn_attrs.no_sanitize.contains(SanitizerSet::CFI)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1559,25 +1564,29 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||||||
llfn: &'ll Value,
|
llfn: &'ll Value,
|
||||||
) -> Option<llvm::OperandBundleDef<'ll>> {
|
) -> Option<llvm::OperandBundleDef<'ll>> {
|
||||||
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
|
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
|
||||||
let kcfi_bundle =
|
let kcfi_bundle = if self.tcx.sess.is_sanitizer_kcfi_enabled()
|
||||||
if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
|
&& let Some(fn_abi) = fn_abi
|
||||||
if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::KCFI) {
|
&& is_indirect_call
|
||||||
return None;
|
{
|
||||||
}
|
if let Some(fn_attrs) = fn_attrs
|
||||||
|
&& fn_attrs.no_sanitize.contains(SanitizerSet::KCFI)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let mut options = TypeIdOptions::empty();
|
let mut options = TypeIdOptions::empty();
|
||||||
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||||
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
|
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
|
||||||
}
|
}
|
||||||
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||||
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
|
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
|
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
|
||||||
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
|
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
kcfi_bundle
|
kcfi_bundle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,8 +46,8 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
|
|||||||
llfn
|
llfn
|
||||||
} else {
|
} else {
|
||||||
let instance_def_id = instance.def_id();
|
let instance_def_id = instance.def_id();
|
||||||
let llfn = if tcx.sess.target.arch == "x86" &&
|
let llfn = if tcx.sess.target.arch == "x86"
|
||||||
let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
|
&& let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
|
||||||
{
|
{
|
||||||
// Fix for https://github.com/rust-lang/rust/issues/104453
|
// Fix for https://github.com/rust-lang/rust/issues/104453
|
||||||
// On x86 Windows, LLVM uses 'L' as the prefix for any private
|
// On x86 Windows, LLVM uses 'L' as the prefix for any private
|
||||||
@ -60,8 +60,18 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
|
|||||||
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the
|
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the
|
||||||
// existing logic below to set the Storage Class, but it has an
|
// existing logic below to set the Storage Class, but it has an
|
||||||
// exemption for MinGW for backwards compatability.
|
// exemption for MinGW for backwards compatability.
|
||||||
let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi, Some(instance));
|
let llfn = cx.declare_fn(
|
||||||
unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); }
|
&common::i686_decorated_name(
|
||||||
|
&dllimport,
|
||||||
|
common::is_mingw_gnu_toolchain(&tcx.sess.target),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
fn_abi,
|
||||||
|
Some(instance),
|
||||||
|
);
|
||||||
|
unsafe {
|
||||||
|
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
|
||||||
|
}
|
||||||
llfn
|
llfn
|
||||||
} else {
|
} else {
|
||||||
cx.declare_fn(sym, fn_abi, Some(instance))
|
cx.declare_fn(sym, fn_abi, Some(instance))
|
||||||
|
@ -182,10 +182,17 @@ fn check_and_apply_linkage<'ll, 'tcx>(
|
|||||||
llvm::LLVMSetInitializer(g2, g1);
|
llvm::LLVMSetInitializer(g2, g1);
|
||||||
g2
|
g2
|
||||||
}
|
}
|
||||||
} else if cx.tcx.sess.target.arch == "x86" &&
|
} else if cx.tcx.sess.target.arch == "x86"
|
||||||
let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym)
|
&& let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym)
|
||||||
{
|
{
|
||||||
cx.declare_global(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), true), llty)
|
cx.declare_global(
|
||||||
|
&common::i686_decorated_name(
|
||||||
|
&dllimport,
|
||||||
|
common::is_mingw_gnu_toolchain(&cx.tcx.sess.target),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
llty,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// Generate an external declaration.
|
// Generate an external declaration.
|
||||||
// FIXME(nagisa): investigate whether it can be changed into define_global
|
// FIXME(nagisa): investigate whether it can be changed into define_global
|
||||||
|
@ -75,7 +75,10 @@ fn make_mir_scope<'ll, 'tcx>(
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(vars) = variables && !vars.contains(scope) && scope_data.inlined.is_none() {
|
if let Some(vars) = variables
|
||||||
|
&& !vars.contains(scope)
|
||||||
|
&& scope_data.inlined.is_none()
|
||||||
|
{
|
||||||
// Do not create a DIScope if there are no variables defined in this
|
// Do not create a DIScope if there are no variables defined in this
|
||||||
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
|
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
|
||||||
debug_context.scopes[scope] = parent_scope;
|
debug_context.scopes[scope] = parent_scope;
|
||||||
|
@ -537,7 +537,9 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||||||
|
|
||||||
// Only "class" methods are generally understood by LLVM,
|
// Only "class" methods are generally understood by LLVM,
|
||||||
// so avoid methods on other types (e.g., `<*mut T>::null`).
|
// so avoid methods on other types (e.g., `<*mut T>::null`).
|
||||||
if let ty::Adt(def, ..) = impl_self_ty.kind() && !def.is_box() {
|
if let ty::Adt(def, ..) = impl_self_ty.kind()
|
||||||
|
&& !def.is_box()
|
||||||
|
{
|
||||||
// Again, only create type information if full debuginfo is enabled
|
// Again, only create type information if full debuginfo is enabled
|
||||||
if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
|
if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
|
||||||
{
|
{
|
||||||
|
@ -368,17 +368,25 @@ fn link_rlib<'a>(
|
|||||||
let NativeLibKind::Static { bundle: None | Some(true), .. } = lib.kind else {
|
let NativeLibKind::Static { bundle: None | Some(true), .. } = lib.kind else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if flavor == RlibFlavor::Normal && let Some(filename) = lib.filename {
|
if flavor == RlibFlavor::Normal
|
||||||
|
&& let Some(filename) = lib.filename
|
||||||
|
{
|
||||||
let path = find_native_static_library(filename.as_str(), true, &lib_search_paths, sess);
|
let path = find_native_static_library(filename.as_str(), true, &lib_search_paths, sess);
|
||||||
let src = read(path).map_err(|e| sess.emit_fatal(errors::ReadFileError {message: e }))?;
|
let src =
|
||||||
|
read(path).map_err(|e| sess.emit_fatal(errors::ReadFileError { message: e }))?;
|
||||||
let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src);
|
let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src);
|
||||||
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
|
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
|
||||||
packed_bundled_libs.push(wrapper_file);
|
packed_bundled_libs.push(wrapper_file);
|
||||||
} else {
|
} else {
|
||||||
let path =
|
let path = find_native_static_library(
|
||||||
find_native_static_library(lib.name.as_str(), lib.verbatim, &lib_search_paths, sess);
|
lib.name.as_str(),
|
||||||
|
lib.verbatim,
|
||||||
|
&lib_search_paths,
|
||||||
|
sess,
|
||||||
|
);
|
||||||
ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| {
|
ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| {
|
||||||
sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error })});
|
sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error })
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,8 +238,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||||||
&& let Some(fn_sig) = fn_sig()
|
&& let Some(fn_sig) = fn_sig()
|
||||||
&& fn_sig.skip_binder().abi() != abi::Abi::Rust
|
&& fn_sig.skip_binder().abi() != abi::Abi::Rust
|
||||||
{
|
{
|
||||||
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
|
struct_span_err!(
|
||||||
.emit();
|
tcx.sess,
|
||||||
|
attr.span,
|
||||||
|
E0737,
|
||||||
|
"`#[track_caller]` requires Rust ABI"
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
if is_closure
|
if is_closure
|
||||||
&& !tcx.features().closure_track_caller
|
&& !tcx.features().closure_track_caller
|
||||||
@ -435,17 +440,18 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||||||
&& let [item] = items.as_slice()
|
&& let [item] = items.as_slice()
|
||||||
&& let Some((sym::align, literal)) = item.name_value_literal()
|
&& let Some((sym::align, literal)) = item.name_value_literal()
|
||||||
{
|
{
|
||||||
rustc_attr::parse_alignment(&literal.kind).map_err(|msg| {
|
rustc_attr::parse_alignment(&literal.kind)
|
||||||
struct_span_err!(
|
.map_err(|msg| {
|
||||||
tcx.sess.diagnostic(),
|
struct_span_err!(
|
||||||
attr.span,
|
tcx.sess.diagnostic(),
|
||||||
E0589,
|
attr.span,
|
||||||
"invalid `repr(align)` attribute: {}",
|
E0589,
|
||||||
msg
|
"invalid `repr(align)` attribute: {}",
|
||||||
)
|
msg
|
||||||
.emit();
|
)
|
||||||
})
|
.emit();
|
||||||
.ok()
|
})
|
||||||
|
.ok()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -626,10 +632,7 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|||||||
&& let ty::AssocItemContainer::ImplContainer = impl_item.container
|
&& let ty::AssocItemContainer::ImplContainer = impl_item.container
|
||||||
&& let Some(trait_item) = impl_item.trait_item_def_id
|
&& let Some(trait_item) = impl_item.trait_item_def_id
|
||||||
{
|
{
|
||||||
return tcx
|
return tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER);
|
||||||
.codegen_fn_attrs(trait_item)
|
|
||||||
.flags
|
|
||||||
.intersects(CodegenFnAttrFlags::TRACK_CALLER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
|
@ -1555,7 +1555,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock {
|
fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock {
|
||||||
if let Some((cached_bb, cached_reason)) = self.terminate_block && reason == cached_reason {
|
if let Some((cached_bb, cached_reason)) = self.terminate_block
|
||||||
|
&& reason == cached_reason
|
||||||
|
{
|
||||||
return cached_bb;
|
return cached_bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,9 +117,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
sym::vtable_size => {
|
sym::vtable_size => {
|
||||||
let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
|
let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
|
||||||
bx.range_metadata(value, WrappingRange { start: 0, end: size_bound });
|
bx.range_metadata(value, WrappingRange { start: 0, end: size_bound });
|
||||||
},
|
}
|
||||||
// Alignment is always nonzero.
|
// Alignment is always nonzero.
|
||||||
sym::vtable_align => bx.range_metadata(value, WrappingRange { start: 1, end: !0 }),
|
sym::vtable_align => {
|
||||||
|
bx.range_metadata(value, WrappingRange { start: 1, end: !0 })
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
value
|
value
|
||||||
@ -220,9 +222,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
} else {
|
} else {
|
||||||
bx.exactudiv(args[0].immediate(), args[1].immediate())
|
bx.exactudiv(args[0].immediate(), args[1].immediate())
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
|
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType {
|
||||||
|
span,
|
||||||
|
name,
|
||||||
|
ty,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,7 +244,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType { span, name, ty: arg_tys[0] });
|
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType {
|
||||||
|
span,
|
||||||
|
name,
|
||||||
|
ty: arg_tys[0],
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,11 +256,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
|
|
||||||
sym::float_to_int_unchecked => {
|
sym::float_to_int_unchecked => {
|
||||||
if float_type_width(arg_tys[0]).is_none() {
|
if float_type_width(arg_tys[0]).is_none() {
|
||||||
bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: arg_tys[0] });
|
bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked {
|
||||||
|
span,
|
||||||
|
ty: arg_tys[0],
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
|
let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
|
||||||
bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: ret_ty });
|
bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked {
|
||||||
|
span,
|
||||||
|
ty: ret_ty,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if signed {
|
if signed {
|
||||||
@ -299,7 +315,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let invalid_monomorphization = |ty| {
|
let invalid_monomorphization = |ty| {
|
||||||
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
|
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType {
|
||||||
|
span,
|
||||||
|
name,
|
||||||
|
ty,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
match instruction {
|
match instruction {
|
||||||
@ -319,7 +339,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
cmp = bx.ptrtoint(cmp, bx.type_isize());
|
cmp = bx.ptrtoint(cmp, bx.type_isize());
|
||||||
src = bx.ptrtoint(src, bx.type_isize());
|
src = bx.ptrtoint(src, bx.type_isize());
|
||||||
}
|
}
|
||||||
let pair = bx.atomic_cmpxchg(dst, cmp, src, parse_ordering(bx, success), parse_ordering(bx, failure), weak);
|
let pair = bx.atomic_cmpxchg(
|
||||||
|
dst,
|
||||||
|
cmp,
|
||||||
|
src,
|
||||||
|
parse_ordering(bx, success),
|
||||||
|
parse_ordering(bx, failure),
|
||||||
|
weak,
|
||||||
|
);
|
||||||
let val = bx.extract_value(pair, 0);
|
let val = bx.extract_value(pair, 0);
|
||||||
let success = bx.extract_value(pair, 1);
|
let success = bx.extract_value(pair, 1);
|
||||||
let val = bx.from_immediate(val);
|
let val = bx.from_immediate(val);
|
||||||
@ -345,11 +372,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
// Some platforms do not support atomic operations on pointers,
|
// Some platforms do not support atomic operations on pointers,
|
||||||
// so we cast to integer first...
|
// so we cast to integer first...
|
||||||
let llty = bx.type_isize();
|
let llty = bx.type_isize();
|
||||||
let result = bx.atomic_load(llty, source, parse_ordering(bx, ordering), size);
|
let result = bx.atomic_load(
|
||||||
|
llty,
|
||||||
|
source,
|
||||||
|
parse_ordering(bx, ordering),
|
||||||
|
size,
|
||||||
|
);
|
||||||
// ... and then cast the result back to a pointer
|
// ... and then cast the result back to a pointer
|
||||||
bx.inttoptr(result, bx.backend_type(layout))
|
bx.inttoptr(result, bx.backend_type(layout))
|
||||||
} else {
|
} else {
|
||||||
bx.atomic_load(bx.backend_type(layout), source, parse_ordering(bx, ordering), size)
|
bx.atomic_load(
|
||||||
|
bx.backend_type(layout),
|
||||||
|
source,
|
||||||
|
parse_ordering(bx, ordering),
|
||||||
|
size,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return invalid_monomorphization(ty);
|
return invalid_monomorphization(ty);
|
||||||
@ -375,12 +412,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
"fence" => {
|
"fence" => {
|
||||||
bx.atomic_fence(parse_ordering(bx, ordering), SynchronizationScope::CrossThread);
|
bx.atomic_fence(
|
||||||
|
parse_ordering(bx, ordering),
|
||||||
|
SynchronizationScope::CrossThread,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
"singlethreadfence" => {
|
"singlethreadfence" => {
|
||||||
bx.atomic_fence(parse_ordering(bx, ordering), SynchronizationScope::SingleThread);
|
bx.atomic_fence(
|
||||||
|
parse_ordering(bx, ordering),
|
||||||
|
SynchronizationScope::SingleThread,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,17 +239,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
};
|
};
|
||||||
if let OperandValueKind::Immediate(out_scalar) = cast_kind
|
if let OperandValueKind::Immediate(out_scalar) = cast_kind
|
||||||
&& in_scalar.size(self.cx) == out_scalar.size(self.cx)
|
&& in_scalar.size(self.cx) == out_scalar.size(self.cx)
|
||||||
{
|
{
|
||||||
let operand_bty = bx.backend_type(operand.layout);
|
let operand_bty = bx.backend_type(operand.layout);
|
||||||
let cast_bty = bx.backend_type(cast);
|
let cast_bty = bx.backend_type(cast);
|
||||||
Some(OperandValue::Immediate(self.transmute_immediate(
|
Some(OperandValue::Immediate(self.transmute_immediate(
|
||||||
bx,
|
bx,
|
||||||
imm,
|
imm,
|
||||||
in_scalar,
|
in_scalar,
|
||||||
operand_bty,
|
operand_bty,
|
||||||
out_scalar,
|
out_scalar,
|
||||||
cast_bty,
|
cast_bty,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
|||||||
hir::Node::Ctor(_)
|
hir::Node::Ctor(_)
|
||||||
| hir::Node::AnonConst(_)
|
| hir::Node::AnonConst(_)
|
||||||
| hir::Node::ConstBlock(_)
|
| hir::Node::ConstBlock(_)
|
||||||
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => hir::Constness::Const,
|
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => {
|
||||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx.generics_of(def_id).host_effect_index.map_or(hir::Constness::NotConst, |_| hir::Constness::Const),
|
hir::Constness::Const
|
||||||
|
}
|
||||||
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx
|
||||||
|
.generics_of(def_id)
|
||||||
|
.host_effect_index
|
||||||
|
.map_or(hir::Constness::NotConst, |_| hir::Constness::Const),
|
||||||
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
|
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
|
||||||
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
|
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
|
||||||
// foreign items cannot be evaluated at compile-time.
|
// foreign items cannot be evaluated at compile-time.
|
||||||
|
@ -268,7 +268,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
NullaryOp(ref null_op, ty) => {
|
NullaryOp(ref null_op, ty) => {
|
||||||
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
|
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
|
||||||
let layout = self.layout_of(ty)?;
|
let layout = self.layout_of(ty)?;
|
||||||
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() {
|
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op
|
||||||
|
&& layout.is_unsized()
|
||||||
|
{
|
||||||
span_bug!(
|
span_bug!(
|
||||||
self.frame().current_span(),
|
self.frame().current_span(),
|
||||||
"{null_op:?} MIR operator called for unsized type {ty}",
|
"{null_op:?} MIR operator called for unsized type {ty}",
|
||||||
|
@ -464,7 +464,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
|
|
||||||
Rvalue::Aggregate(kind, ..) => {
|
Rvalue::Aggregate(kind, ..) => {
|
||||||
if let AggregateKind::Generator(def_id, ..) = kind.as_ref()
|
if let AggregateKind::Generator(def_id, ..) = kind.as_ref()
|
||||||
&& let Some(generator_kind @ hir::GeneratorKind::Async(..)) = self.tcx.generator_kind(def_id)
|
&& let Some(generator_kind @ hir::GeneratorKind::Async(..)) =
|
||||||
|
self.tcx.generator_kind(def_id)
|
||||||
{
|
{
|
||||||
self.check_op(ops::Generator(generator_kind));
|
self.check_op(ops::Generator(generator_kind));
|
||||||
}
|
}
|
||||||
@ -579,8 +580,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::BinaryOp(op, box (lhs, rhs))
|
Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
|
||||||
| Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
|
|
||||||
let lhs_ty = lhs.ty(self.body, self.tcx);
|
let lhs_ty = lhs.ty(self.body, self.tcx);
|
||||||
let rhs_ty = rhs.ty(self.body, self.tcx);
|
let rhs_ty = rhs.ty(self.body, self.tcx);
|
||||||
|
|
||||||
@ -588,18 +588,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
// Int, bool, and char operations are fine.
|
// Int, bool, and char operations are fine.
|
||||||
} else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
|
} else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
|
||||||
assert_eq!(lhs_ty, rhs_ty);
|
assert_eq!(lhs_ty, rhs_ty);
|
||||||
assert!(
|
assert!(matches!(
|
||||||
matches!(
|
op,
|
||||||
op,
|
BinOp::Eq
|
||||||
BinOp::Eq
|
|
||||||
| BinOp::Ne
|
| BinOp::Ne
|
||||||
| BinOp::Le
|
| BinOp::Le
|
||||||
| BinOp::Lt
|
| BinOp::Lt
|
||||||
| BinOp::Ge
|
| BinOp::Ge
|
||||||
| BinOp::Gt
|
| BinOp::Gt
|
||||||
| BinOp::Offset
|
| BinOp::Offset
|
||||||
)
|
));
|
||||||
);
|
|
||||||
|
|
||||||
self.check_op(ops::RawPtrComparison);
|
self.check_op(ops::RawPtrComparison);
|
||||||
} else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() {
|
} else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() {
|
||||||
@ -947,7 +945,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
if self.span.allows_unstable(gate) {
|
if self.span.allows_unstable(gate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(implied_by_gate) = implied_by && self.span.allows_unstable(implied_by_gate) {
|
if let Some(implied_by_gate) = implied_by
|
||||||
|
&& self.span.allows_unstable(implied_by_gate)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,10 +311,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||||||
ccx.const_kind(),
|
ccx.const_kind(),
|
||||||
));
|
));
|
||||||
|
|
||||||
if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() {
|
if let Some(feature) = feature
|
||||||
err.help(format!(
|
&& ccx.tcx.sess.is_nightly_build()
|
||||||
"add `#![feature({feature})]` to the crate attributes to enable",
|
{
|
||||||
));
|
err.help(format!("add `#![feature({feature})]` to the crate attributes to enable",));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ConstContext::Static(_) = ccx.const_kind() {
|
if let ConstContext::Static(_) = ccx.const_kind() {
|
||||||
|
@ -1290,7 +1290,9 @@ fn ice_path() -> &'static Option<PathBuf> {
|
|||||||
if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
|
if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if let Some(s) = std::env::var_os("RUST_BACKTRACE") && s == "0" {
|
if let Some(s) = std::env::var_os("RUST_BACKTRACE")
|
||||||
|
&& s == "0"
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let mut path = match std::env::var_os("RUSTC_ICE") {
|
let mut path = match std::env::var_os("RUSTC_ICE") {
|
||||||
@ -1357,8 +1359,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
|
|||||||
eprintln!();
|
eprintln!();
|
||||||
|
|
||||||
if let Some(ice_path) = ice_path()
|
if let Some(ice_path) = ice_path()
|
||||||
&& let Ok(mut out) =
|
&& let Ok(mut out) = File::options().create(true).append(true).open(&ice_path)
|
||||||
File::options().create(true).append(true).open(&ice_path)
|
|
||||||
{
|
{
|
||||||
// The current implementation always returns `Some`.
|
// The current implementation always returns `Some`.
|
||||||
let location = info.location().unwrap();
|
let location = info.location().unwrap();
|
||||||
|
@ -337,9 +337,7 @@ pub trait Emitter: Translate {
|
|||||||
&& last_name != name
|
&& last_name != name
|
||||||
{
|
{
|
||||||
let descr = macro_kind.descr();
|
let descr = macro_kind.descr();
|
||||||
format!(
|
format!(" which comes from the expansion of the {descr} `{last_name}`",)
|
||||||
" which comes from the expansion of the {descr} `{last_name}`",
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
@ -1935,7 +1933,9 @@ impl EmitterWriter {
|
|||||||
is_multiline,
|
is_multiline,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if let DisplaySuggestion::Add = show_code_change && is_item_attribute {
|
if let DisplaySuggestion::Add = show_code_change
|
||||||
|
&& is_item_attribute
|
||||||
|
{
|
||||||
// The suggestion adds an entire line of code, ending on a newline, so we'll also
|
// The suggestion adds an entire line of code, ending on a newline, so we'll also
|
||||||
// print the *following* line, to provide context of what we're advising people to
|
// print the *following* line, to provide context of what we're advising people to
|
||||||
// do. Otherwise you would only see contextless code that can be confused for
|
// do. Otherwise you would only see contextless code that can be confused for
|
||||||
|
@ -1673,7 +1673,11 @@ impl HandlerInner {
|
|||||||
let _ = write!(
|
let _ = write!(
|
||||||
&mut out,
|
&mut out,
|
||||||
"delayed span bug: {}\n{}\n",
|
"delayed span bug: {}\n{}\n",
|
||||||
bug.inner.styled_message().iter().filter_map(|(msg, _)| msg.as_str()).collect::<String>(),
|
bug.inner
|
||||||
|
.styled_message()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(msg, _)| msg.as_str())
|
||||||
|
.collect::<String>(),
|
||||||
&bug.note
|
&bug.note
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -151,12 +151,14 @@ fn misformed_fluent() {
|
|||||||
primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. },
|
primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. },
|
||||||
fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. },
|
fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. },
|
||||||
} = &err
|
} = &err
|
||||||
&& let [FluentError::ResolverError(ResolverError::Reference(
|
&& let [
|
||||||
ReferenceKind::Message { id, .. }
|
FluentError::ResolverError(ResolverError::Reference(
|
||||||
| ReferenceKind::Variable { id, .. },
|
ReferenceKind::Message { id, .. } | ReferenceKind::Variable { id, .. },
|
||||||
))] = &**errs
|
)),
|
||||||
|
] = &**errs
|
||||||
&& id == "name"
|
&& id == "name"
|
||||||
{} else {
|
{
|
||||||
|
} else {
|
||||||
panic!("{err:#?}")
|
panic!("{err:#?}")
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -176,12 +178,14 @@ fn misformed_fluent() {
|
|||||||
primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. },
|
primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. },
|
||||||
fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. },
|
fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. },
|
||||||
} = &err
|
} = &err
|
||||||
&& let [FluentError::ResolverError(ResolverError::Reference(
|
&& let [
|
||||||
ReferenceKind::Message { id, .. }
|
FluentError::ResolverError(ResolverError::Reference(
|
||||||
| ReferenceKind::Variable { id, .. },
|
ReferenceKind::Message { id, .. } | ReferenceKind::Variable { id, .. },
|
||||||
))] = &**errs
|
)),
|
||||||
|
] = &**errs
|
||||||
&& id == "oops"
|
&& id == "oops"
|
||||||
{} else {
|
{
|
||||||
|
} else {
|
||||||
panic!("{err:#?}")
|
panic!("{err:#?}")
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -47,7 +47,9 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> {
|
fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> {
|
||||||
if attr.has_name(sym::feature) && let Some(list) = attr.meta_item_list() {
|
if attr.has_name(sym::feature)
|
||||||
|
&& let Some(list) = attr.meta_item_list()
|
||||||
|
{
|
||||||
list
|
list
|
||||||
} else {
|
} else {
|
||||||
ThinVec::new()
|
ThinVec::new()
|
||||||
@ -69,7 +71,9 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
|
|||||||
if mi.is_word() {
|
if mi.is_word() {
|
||||||
let name = mi.name_or_empty();
|
let name = mi.name_or_empty();
|
||||||
let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
|
let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
|
||||||
if let Some(edition) = edition && edition > features_edition {
|
if let Some(edition) = edition
|
||||||
|
&& edition > features_edition
|
||||||
|
{
|
||||||
features_edition = edition;
|
features_edition = edition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,7 +252,8 @@ impl<'a> StripUnconfigured<'a> {
|
|||||||
let trees: Vec<_> = stream
|
let trees: Vec<_> = stream
|
||||||
.0
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|tree| match tree.clone() {
|
.flat_map(|tree| {
|
||||||
|
match tree.clone() {
|
||||||
AttrTokenTree::Attributes(mut data) => {
|
AttrTokenTree::Attributes(mut data) => {
|
||||||
data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
|
data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
|
||||||
|
|
||||||
@ -263,18 +268,17 @@ impl<'a> StripUnconfigured<'a> {
|
|||||||
}
|
}
|
||||||
AttrTokenTree::Delimited(sp, delim, mut inner) => {
|
AttrTokenTree::Delimited(sp, delim, mut inner) => {
|
||||||
inner = self.configure_tokens(&inner);
|
inner = self.configure_tokens(&inner);
|
||||||
Some(AttrTokenTree::Delimited(sp, delim, inner))
|
Some(AttrTokenTree::Delimited(sp, delim, inner)).into_iter()
|
||||||
.into_iter()
|
|
||||||
}
|
}
|
||||||
AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(nt) = &token.kind => {
|
AttrTokenTree::Token(ref token, _)
|
||||||
panic!(
|
if let TokenKind::Interpolated(nt) = &token.kind =>
|
||||||
"Nonterminal should have been flattened at {:?}: {:?}",
|
{
|
||||||
token.span, nt
|
panic!("Nonterminal should have been flattened at {:?}: {:?}", token.span, nt);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
AttrTokenTree::Token(token, spacing) => {
|
AttrTokenTree::Token(token, spacing) => {
|
||||||
Some(AttrTokenTree::Token(token, spacing)).into_iter()
|
Some(AttrTokenTree::Token(token, spacing)).into_iter()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
AttrTokenStream::new(trees)
|
AttrTokenStream::new(trees)
|
||||||
|
@ -716,18 +716,18 @@ fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
|
|||||||
match rhs {
|
match rhs {
|
||||||
mbe::TokenTree::Delimited(_sp, d) => {
|
mbe::TokenTree::Delimited(_sp, d) => {
|
||||||
let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| {
|
let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| {
|
||||||
if let mbe::TokenTree::Token(ident) = ident &&
|
if let mbe::TokenTree::Token(ident) = ident
|
||||||
let TokenKind::Ident(ident, _) = ident.kind &&
|
&& let TokenKind::Ident(ident, _) = ident.kind
|
||||||
ident == sym::compile_error &&
|
&& ident == sym::compile_error
|
||||||
let mbe::TokenTree::Token(bang) = bang &&
|
&& let mbe::TokenTree::Token(bang) = bang
|
||||||
let TokenKind::Not = bang.kind &&
|
&& let TokenKind::Not = bang.kind
|
||||||
let mbe::TokenTree::Delimited(_, del) = args &&
|
&& let mbe::TokenTree::Delimited(_, del) = args
|
||||||
del.delim != Delimiter::Invisible
|
&& del.delim != Delimiter::Invisible
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if has_compile_error { true } else { d.tts.iter().any(has_compile_error_macro) }
|
if has_compile_error { true } else { d.tts.iter().any(has_compile_error_macro) }
|
||||||
}
|
}
|
||||||
|
@ -124,8 +124,7 @@ fn parse_depth<'sess>(
|
|||||||
&& let Ok(n_usize) = usize::try_from(n_u128)
|
&& let Ok(n_usize) = usize::try_from(n_u128)
|
||||||
{
|
{
|
||||||
Ok(n_usize)
|
Ok(n_usize)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
let msg = "only unsuffixes integer literals are supported in meta-variable expressions";
|
let msg = "only unsuffixes integer literals are supported in meta-variable expressions";
|
||||||
Err(sess.span_diagnostic.struct_span_err(span, msg))
|
Err(sess.span_diagnostic.struct_span_err(span, msg))
|
||||||
}
|
}
|
||||||
@ -137,15 +136,16 @@ fn parse_ident<'sess>(
|
|||||||
sess: &'sess ParseSess,
|
sess: &'sess ParseSess,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> PResult<'sess, Ident> {
|
) -> PResult<'sess, Ident> {
|
||||||
if let Some(tt) = iter.next() && let TokenTree::Token(token, _) = tt {
|
if let Some(tt) = iter.next()
|
||||||
|
&& let TokenTree::Token(token, _) = tt
|
||||||
|
{
|
||||||
if let Some((elem, false)) = token.ident() {
|
if let Some((elem, false)) = token.ident() {
|
||||||
return Ok(elem);
|
return Ok(elem);
|
||||||
}
|
}
|
||||||
let token_str = pprust::token_to_string(token);
|
let token_str = pprust::token_to_string(token);
|
||||||
let mut err = sess.span_diagnostic.struct_span_err(
|
let mut err = sess
|
||||||
span,
|
.span_diagnostic
|
||||||
format!("expected identifier, found `{}`", &token_str)
|
.struct_span_err(span, format!("expected identifier, found `{}`", &token_str));
|
||||||
);
|
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
token.span,
|
token.span,
|
||||||
format!("try removing `{}`", &token_str),
|
format!("try removing `{}`", &token_str),
|
||||||
|
@ -91,7 +91,9 @@ pub(crate) fn mod_dir_path(
|
|||||||
inline: Inline,
|
inline: Inline,
|
||||||
) -> (PathBuf, DirOwnership) {
|
) -> (PathBuf, DirOwnership) {
|
||||||
match inline {
|
match inline {
|
||||||
Inline::Yes if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) => {
|
Inline::Yes
|
||||||
|
if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) =>
|
||||||
|
{
|
||||||
// For inline modules file path from `#[path]` is actually the directory path
|
// For inline modules file path from `#[path]` is actually the directory path
|
||||||
// for historical reasons, so we don't pop the last segment here.
|
// for historical reasons, so we don't pop the last segment here.
|
||||||
(file_path, DirOwnership::Owned { relative: None })
|
(file_path, DirOwnership::Owned { relative: None })
|
||||||
|
@ -226,9 +226,8 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => {
|
Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => trees
|
||||||
trees.push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span }))
|
.push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })),
|
||||||
}
|
|
||||||
|
|
||||||
Interpolated(nt) => {
|
Interpolated(nt) => {
|
||||||
let stream = TokenStream::from_nonterminal_ast(&nt);
|
let stream = TokenStream::from_nonterminal_ast(&nt);
|
||||||
|
@ -517,8 +517,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let DefKind::AssocConst = def_kind
|
if let DefKind::AssocConst = def_kind
|
||||||
&& let Some(t) = term.ty() && (t.is_enum() || t.references_error())
|
&& let Some(t) = term.ty()
|
||||||
&& tcx.features().associated_const_equality {
|
&& (t.is_enum() || t.references_error())
|
||||||
|
&& tcx.features().associated_const_equality
|
||||||
|
{
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
binding.span,
|
binding.span,
|
||||||
"if equating a const, try wrapping with braces",
|
"if equating a const, try wrapping with braces",
|
||||||
|
@ -432,9 +432,11 @@ pub(crate) fn check_generic_arg_count(
|
|||||||
let infer_lifetimes =
|
let infer_lifetimes =
|
||||||
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
|
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
|
||||||
|
|
||||||
if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
|
if gen_pos != GenericArgPosition::Type
|
||||||
prohibit_assoc_ty_binding(tcx, b.span, None);
|
&& let Some(b) = gen_args.bindings.first()
|
||||||
}
|
{
|
||||||
|
prohibit_assoc_ty_binding(tcx, b.span, None);
|
||||||
|
}
|
||||||
|
|
||||||
let explicit_late_bound =
|
let explicit_late_bound =
|
||||||
prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
|
prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
|
||||||
|
@ -18,18 +18,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
if let hir::Node::Item(hir::Item {
|
if let hir::Node::Item(hir::Item {
|
||||||
kind:
|
kind:
|
||||||
hir::ItemKind::Impl(hir::Impl {
|
hir::ItemKind::Impl(hir::Impl {
|
||||||
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
|
self_ty: impl_self_ty,
|
||||||
|
of_trait: Some(of_trait_ref),
|
||||||
|
generics,
|
||||||
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
|
}) = tcx.hir().get_by_def_id(parent_id)
|
||||||
|
&& self_ty.hir_id == impl_self_ty.hir_id
|
||||||
{
|
{
|
||||||
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
|
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let of_trait_span = of_trait_ref.path.span;
|
let of_trait_span = of_trait_ref.path.span;
|
||||||
// make sure that we are not calling unwrap to abort during the compilation
|
// make sure that we are not calling unwrap to abort during the compilation
|
||||||
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
|
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
|
||||||
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
|
return;
|
||||||
|
};
|
||||||
|
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
// check if the trait has generics, to make a correct suggestion
|
// check if the trait has generics, to make a correct suggestion
|
||||||
let param_name = generics.params.next_type_param_name(None);
|
let param_name = generics.params.next_type_param_name(None);
|
||||||
|
|
||||||
@ -39,13 +47,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
|
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
|
||||||
};
|
};
|
||||||
diag.multipart_suggestion(
|
diag.multipart_suggestion(
|
||||||
format!("alternatively use a blanket \
|
format!(
|
||||||
|
"alternatively use a blanket \
|
||||||
implementation to implement `{of_trait_name}` for \
|
implementation to implement `{of_trait_name}` for \
|
||||||
all types that also implement `{impl_trait_name}`"),
|
all types that also implement `{impl_trait_name}`"
|
||||||
vec![
|
),
|
||||||
(self_ty.span, param_name),
|
vec![(self_ty.span, param_name), add_generic_sugg],
|
||||||
add_generic_sugg,
|
|
||||||
],
|
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -567,9 +567,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let ty::BoundConstness::ConstIfConst = constness
|
if let ty::BoundConstness::ConstIfConst = constness
|
||||||
&& generics.has_self && !tcx.has_attr(def_id, sym::const_trait)
|
&& generics.has_self
|
||||||
|
&& !tcx.has_attr(def_id, sym::const_trait)
|
||||||
{
|
{
|
||||||
tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } );
|
tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span });
|
||||||
}
|
}
|
||||||
|
|
||||||
(args, arg_count)
|
(args, arg_count)
|
||||||
@ -1919,9 +1920,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
} else {
|
} else {
|
||||||
Some((
|
Some((
|
||||||
match segment.res {
|
match segment.res {
|
||||||
Res::PrimTy(ty) => format!("{} `{}`", segment.res.descr(), ty.name()),
|
Res::PrimTy(ty) => {
|
||||||
|
format!("{} `{}`", segment.res.descr(), ty.name())
|
||||||
|
}
|
||||||
Res::Def(_, def_id)
|
Res::Def(_, def_id)
|
||||||
if let Some(name) = self.tcx().opt_item_name(def_id) => {
|
if let Some(name) = self.tcx().opt_item_name(def_id) =>
|
||||||
|
{
|
||||||
format!("{} `{name}`", segment.res.descr())
|
format!("{} `{name}`", segment.res.descr())
|
||||||
}
|
}
|
||||||
Res::Err => "this type".to_string(),
|
Res::Err => "this type".to_string(),
|
||||||
@ -2251,7 +2255,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
err.note(msg);
|
err.note(msg);
|
||||||
}
|
}
|
||||||
for segment in path.segments {
|
for segment in path.segments {
|
||||||
if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper {
|
if let Some(args) = segment.args
|
||||||
|
&& segment.ident.name == kw::SelfUpper
|
||||||
|
{
|
||||||
if generics == 0 {
|
if generics == 0 {
|
||||||
// FIXME(estebank): we could also verify that the arguments being
|
// FIXME(estebank): we could also verify that the arguments being
|
||||||
// work for the `enum`, instead of just looking if it takes *any*.
|
// work for the `enum`, instead of just looking if it takes *any*.
|
||||||
@ -2633,7 +2639,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, a)| {
|
.map(|(i, a)| {
|
||||||
if let hir::TyKind::Infer = a.kind && !self.allow_ty_infer() {
|
if let hir::TyKind::Infer = a.kind
|
||||||
|
&& !self.allow_ty_infer()
|
||||||
|
{
|
||||||
if let Some(suggested_ty) =
|
if let Some(suggested_ty) =
|
||||||
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
|
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
|
||||||
{
|
{
|
||||||
@ -2662,7 +2670,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
self.ast_ty_to_ty(output)
|
self.ast_ty_to_ty(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx,),
|
hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx),
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(?output_ty);
|
debug!(?output_ty);
|
||||||
|
@ -481,8 +481,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||||||
fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi);
|
fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi);
|
||||||
}
|
}
|
||||||
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
|
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
|
||||||
let trait_args =
|
let trait_args = GenericArgs::identity_for_item(tcx, id.owner_id);
|
||||||
GenericArgs::identity_for_item(tcx, id.owner_id);
|
|
||||||
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
|
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
|
||||||
tcx,
|
tcx,
|
||||||
assoc_item,
|
assoc_item,
|
||||||
@ -502,7 +501,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||||||
}
|
}
|
||||||
DefKind::OpaqueTy => {
|
DefKind::OpaqueTy => {
|
||||||
let origin = tcx.opaque_type_origin(id.owner_id.def_id);
|
let origin = tcx.opaque_type_origin(id.owner_id.def_id);
|
||||||
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
|
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
|
||||||
|
| hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
|
||||||
&& let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id)
|
&& let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id)
|
||||||
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
|
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
|
||||||
{
|
{
|
||||||
@ -589,7 +589,9 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||||||
}
|
}
|
||||||
DefKind::GlobalAsm => {
|
DefKind::GlobalAsm => {
|
||||||
let it = tcx.hir().item(id);
|
let it = tcx.hir().item(id);
|
||||||
let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) };
|
let hir::ItemKind::GlobalAsm(asm) = it.kind else {
|
||||||
|
span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it)
|
||||||
|
};
|
||||||
InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id);
|
InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -873,10 +875,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
|
|||||||
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
|
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
|
||||||
ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
|
ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
|
||||||
ty::Array(t, _clen)
|
ty::Array(t, _clen)
|
||||||
if matches!(
|
if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) =>
|
||||||
t.kind(),
|
|
||||||
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)
|
|
||||||
) =>
|
|
||||||
{ /* struct([f32; 4]) is ok */ }
|
{ /* struct([f32; 4]) is ok */ }
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
@ -899,17 +898,17 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
|
|||||||
for attr in tcx.get_attrs(def.did(), sym::repr) {
|
for attr in tcx.get_attrs(def.did(), sym::repr) {
|
||||||
for r in attr::parse_repr_attr(&tcx.sess, attr) {
|
for r in attr::parse_repr_attr(&tcx.sess, attr) {
|
||||||
if let attr::ReprPacked(pack) = r
|
if let attr::ReprPacked(pack) = r
|
||||||
&& let Some(repr_pack) = repr.pack
|
&& let Some(repr_pack) = repr.pack
|
||||||
&& pack as u64 != repr_pack.bytes()
|
&& pack as u64 != repr_pack.bytes()
|
||||||
{
|
{
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
tcx.sess,
|
tcx.sess,
|
||||||
sp,
|
sp,
|
||||||
E0634,
|
E0634,
|
||||||
"type has conflicting packed representation hints"
|
"type has conflicting packed representation hints"
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if repr.align.is_some() {
|
if repr.align.is_some() {
|
||||||
@ -1174,7 +1173,8 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
|
|||||||
let (span, display_discr) = match var.discr {
|
let (span, display_discr) = match var.discr {
|
||||||
ty::VariantDiscr::Explicit(discr_def_id) => {
|
ty::VariantDiscr::Explicit(discr_def_id) => {
|
||||||
// In the case the discriminant is both a duplicate and overflowed, let the user know
|
// In the case the discriminant is both a duplicate and overflowed, let the user know
|
||||||
if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local())
|
if let hir::Node::AnonConst(expr) =
|
||||||
|
tcx.hir().get_by_def_id(discr_def_id.expect_local())
|
||||||
&& let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
|
&& let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
|
||||||
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
|
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
|
||||||
&& *lit_value != dis.val
|
&& *lit_value != dis.val
|
||||||
@ -1303,15 +1303,9 @@ pub(super) fn check_type_params_are_used<'tcx>(
|
|||||||
&& let ty::GenericParamDefKind::Type { .. } = param.kind
|
&& let ty::GenericParamDefKind::Type { .. } = param.kind
|
||||||
{
|
{
|
||||||
let span = tcx.def_span(param.def_id);
|
let span = tcx.def_span(param.def_id);
|
||||||
struct_span_err!(
|
struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name,)
|
||||||
tcx.sess,
|
.span_label(span, "unused type parameter")
|
||||||
span,
|
.emit();
|
||||||
E0091,
|
|
||||||
"type parameter `{}` is unused",
|
|
||||||
param.name,
|
|
||||||
)
|
|
||||||
.span_label(span, "unused type parameter")
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1430,7 +1424,10 @@ fn opaque_type_cycle_error(
|
|||||||
let mut label_match = |ty: Ty<'_>, span| {
|
let mut label_match = |ty: Ty<'_>, span| {
|
||||||
for arg in ty.walk() {
|
for arg in ty.walk() {
|
||||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||||
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind()
|
&& let ty::Alias(
|
||||||
|
ty::Opaque,
|
||||||
|
ty::AliasTy { def_id: captured_def_id, .. },
|
||||||
|
) = *ty.kind()
|
||||||
&& captured_def_id == opaque_def_id.to_def_id()
|
&& captured_def_id == opaque_def_id.to_def_id()
|
||||||
{
|
{
|
||||||
err.span_label(
|
err.span_label(
|
||||||
|
@ -1009,7 +1009,11 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
|
|||||||
});
|
});
|
||||||
self.types.insert(proj.def_id, (infer_ty, proj.args));
|
self.types.insert(proj.def_id, (infer_ty, proj.args));
|
||||||
// Recurse into bounds
|
// Recurse into bounds
|
||||||
for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).iter_instantiated_copied(self.interner(), proj.args) {
|
for (pred, pred_span) in self
|
||||||
|
.interner()
|
||||||
|
.explicit_item_bounds(proj.def_id)
|
||||||
|
.iter_instantiated_copied(self.interner(), proj.args)
|
||||||
|
{
|
||||||
let pred = pred.fold_with(self);
|
let pred = pred.fold_with(self);
|
||||||
let pred = self.ocx.normalize(
|
let pred = self.ocx.normalize(
|
||||||
&ObligationCause::misc(self.span, self.body_id),
|
&ObligationCause::misc(self.span, self.body_id),
|
||||||
@ -1180,7 +1184,8 @@ fn report_trait_method_mismatch<'tcx>(
|
|||||||
if trait_sig.inputs().len() == *i {
|
if trait_sig.inputs().len() == *i {
|
||||||
// Suggestion to change output type. We do not suggest in `async` functions
|
// Suggestion to change output type. We do not suggest in `async` functions
|
||||||
// to avoid complex logic or incorrect output.
|
// to avoid complex logic or incorrect output.
|
||||||
if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind
|
if let ImplItemKind::Fn(sig, _) =
|
||||||
|
&tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind
|
||||||
&& !sig.header.asyncness.is_async()
|
&& !sig.header.asyncness.is_async()
|
||||||
{
|
{
|
||||||
let msg = "change the output type to match the trait";
|
let msg = "change the output type to match the trait";
|
||||||
|
@ -550,9 +550,11 @@ fn infringing_fields_error(
|
|||||||
.entry((ty.clone(), predicate.clone()))
|
.entry((ty.clone(), predicate.clone()))
|
||||||
.or_default()
|
.or_default()
|
||||||
.push(origin.span());
|
.push(origin.span());
|
||||||
if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
|
if let ty::RegionKind::ReEarlyBound(ebr) = *b
|
||||||
bounds.push((b.to_string(), a.to_string(), None));
|
&& ebr.has_name()
|
||||||
}
|
{
|
||||||
|
bounds.push((b.to_string(), a.to_string(), None));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RegionResolutionError::GenericBoundFailure(origin, a, b) => {
|
RegionResolutionError::GenericBoundFailure(origin, a, b) => {
|
||||||
let predicate = format!("{a}: {b}");
|
let predicate = format!("{a}: {b}");
|
||||||
|
@ -212,7 +212,9 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
|
|||||||
let mut is_fn = false;
|
let mut is_fn = false;
|
||||||
let mut is_const_or_static = false;
|
let mut is_const_or_static = false;
|
||||||
|
|
||||||
if let Some(hir_ty) = hir_ty && let hir::TyKind::BareFn(_) = hir_ty.kind {
|
if let Some(hir_ty) = hir_ty
|
||||||
|
&& let hir::TyKind::BareFn(_) = hir_ty.kind
|
||||||
|
{
|
||||||
is_fn = true;
|
is_fn = true;
|
||||||
|
|
||||||
// Check if parent is const or static
|
// Check if parent is const or static
|
||||||
@ -224,10 +226,8 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
|
|||||||
Node::Item(&hir::Item {
|
Node::Item(&hir::Item {
|
||||||
kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
|
kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
|
||||||
..
|
..
|
||||||
}) | Node::TraitItem(&hir::TraitItem {
|
}) | Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. })
|
||||||
kind: hir::TraitItemKind::Const(..),
|
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
|
||||||
..
|
|
||||||
}) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1004,10 +1004,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||||||
&& let Some(lit) = meta.name_value_literal()
|
&& let Some(lit) = meta.name_value_literal()
|
||||||
{
|
{
|
||||||
if seen_attr {
|
if seen_attr {
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(meta.span, "duplicated `implement_via_object` meta item");
|
||||||
meta.span,
|
|
||||||
"duplicated `implement_via_object` meta item",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
seen_attr = true;
|
seen_attr = true;
|
||||||
|
|
||||||
@ -1021,7 +1018,10 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||||||
_ => {
|
_ => {
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
meta.span,
|
meta.span,
|
||||||
format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol),
|
format!(
|
||||||
|
"unknown literal passed to `implement_via_object` attribute: {}",
|
||||||
|
lit.symbol
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1115,8 +1115,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
|
|||||||
|
|
||||||
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
|
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
|
||||||
// Do not try to infer the return type for a impl method coming from a trait
|
// Do not try to infer the return type for a impl method coming from a trait
|
||||||
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
|
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.hir().get_parent(hir_id)
|
||||||
tcx.hir().get_parent(hir_id)
|
|
||||||
&& i.of_trait.is_some()
|
&& i.of_trait.is_some()
|
||||||
{
|
{
|
||||||
icx.astconv().ty_of_fn(
|
icx.astconv().ty_of_fn(
|
||||||
@ -1343,7 +1342,13 @@ fn suggest_impl_trait<'tcx>(
|
|||||||
if ocx.select_where_possible().is_empty()
|
if ocx.select_where_possible().is_empty()
|
||||||
&& let item_ty = infcx.resolve_vars_if_possible(item_ty)
|
&& let item_ty = infcx.resolve_vars_if_possible(item_ty)
|
||||||
&& let Some(item_ty) = item_ty.make_suggestable(tcx, false)
|
&& let Some(item_ty) = item_ty.make_suggestable(tcx, false)
|
||||||
&& let Some(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(args), trait_def_id, assoc_item_def_id, item_ty)
|
&& let Some(sugg) = formatter(
|
||||||
|
tcx,
|
||||||
|
infcx.resolve_vars_if_possible(args),
|
||||||
|
trait_def_id,
|
||||||
|
assoc_item_def_id,
|
||||||
|
item_ty,
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return Some(sugg);
|
return Some(sugg);
|
||||||
}
|
}
|
||||||
|
@ -169,8 +169,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> {
|
|||||||
|
|
||||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
|
if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
|
||||||
&& let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. })
|
&& let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
|
||||||
= self.tcx.opt_rpitit_info(projection_ty.def_id)
|
self.tcx.opt_rpitit_info(projection_ty.def_id)
|
||||||
&& fn_def_id == self.fn_def_id
|
&& fn_def_id == self.fn_def_id
|
||||||
{
|
{
|
||||||
self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args)
|
self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args)
|
||||||
|
@ -389,7 +389,9 @@ fn const_evaluatable_predicates_of(
|
|||||||
let node = tcx.hir().get(hir_id);
|
let node = tcx.hir().get(hir_id);
|
||||||
|
|
||||||
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
|
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
|
||||||
if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(impl_) = item.kind {
|
if let hir::Node::Item(item) = node
|
||||||
|
&& let hir::ItemKind::Impl(impl_) = item.kind
|
||||||
|
{
|
||||||
if let Some(of_trait) = &impl_.of_trait {
|
if let Some(of_trait) = &impl_.of_trait {
|
||||||
debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
|
debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
|
||||||
collector.visit_trait_ref(of_trait);
|
collector.visit_trait_ref(of_trait);
|
||||||
|
@ -1190,7 +1190,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||||||
Scope::Root { opt_parent_item } => {
|
Scope::Root { opt_parent_item } => {
|
||||||
if let Some(parent_item) = opt_parent_item
|
if let Some(parent_item) = opt_parent_item
|
||||||
&& let parent_generics = self.tcx.generics_of(parent_item)
|
&& let parent_generics = self.tcx.generics_of(parent_item)
|
||||||
&& parent_generics.param_def_id_to_index(self.tcx, region_def_id.to_def_id()).is_some()
|
&& parent_generics
|
||||||
|
.param_def_id_to_index(self.tcx, region_def_id.to_def_id())
|
||||||
|
.is_some()
|
||||||
{
|
{
|
||||||
break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id()));
|
break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id()));
|
||||||
}
|
}
|
||||||
@ -1209,13 +1211,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||||||
// regular fns.
|
// regular fns.
|
||||||
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
|
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
|
||||||
&& let hir::LifetimeName::Param(param_id) = lifetime_ref.res
|
&& let hir::LifetimeName::Param(param_id) = lifetime_ref.res
|
||||||
&& let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
|
&& let Some(generics) =
|
||||||
|
self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
|
||||||
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
|
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
|
||||||
&& param.is_elided_lifetime()
|
&& param.is_elided_lifetime()
|
||||||
&& !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
|
&& !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
|
||||||
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
|
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
|
||||||
{
|
{
|
||||||
let mut diag = rustc_session::parse::feature_err(
|
let mut diag = rustc_session::parse::feature_err(
|
||||||
&self.tcx.sess.parse_sess,
|
&self.tcx.sess.parse_sess,
|
||||||
sym::anonymous_lifetime_in_impl_trait,
|
sym::anonymous_lifetime_in_impl_trait,
|
||||||
lifetime_ref.ident.span,
|
lifetime_ref.ident.span,
|
||||||
@ -1225,25 +1228,31 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||||||
if let Some(generics) =
|
if let Some(generics) =
|
||||||
self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id)
|
self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id)
|
||||||
{
|
{
|
||||||
let new_param_sugg = if let Some(span) =
|
let new_param_sugg =
|
||||||
generics.span_for_lifetime_suggestion()
|
if let Some(span) = generics.span_for_lifetime_suggestion() {
|
||||||
{
|
(span, "'a, ".to_owned())
|
||||||
(span, "'a, ".to_owned())
|
} else {
|
||||||
} else {
|
(generics.span, "<'a>".to_owned())
|
||||||
(generics.span, "<'a>".to_owned())
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let lifetime_sugg = match lifetime_ref.suggestion_position() {
|
let lifetime_sugg = match lifetime_ref.suggestion_position() {
|
||||||
(hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()),
|
(hir::LifetimeSuggestionPosition::Normal, span) => {
|
||||||
(hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()),
|
(span, "'a".to_owned())
|
||||||
(hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()),
|
}
|
||||||
(hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()),
|
(hir::LifetimeSuggestionPosition::Ampersand, span) => {
|
||||||
(hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()),
|
(span, "'a ".to_owned())
|
||||||
|
}
|
||||||
|
(hir::LifetimeSuggestionPosition::ElidedPath, span) => {
|
||||||
|
(span, "<'a>".to_owned())
|
||||||
|
}
|
||||||
|
(hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => {
|
||||||
|
(span, "'a, ".to_owned())
|
||||||
|
}
|
||||||
|
(hir::LifetimeSuggestionPosition::ObjectDefault, span) => {
|
||||||
|
(span, "+ 'a".to_owned())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let suggestions = vec![
|
let suggestions = vec![lifetime_sugg, new_param_sugg];
|
||||||
lifetime_sugg,
|
|
||||||
new_param_sugg,
|
|
||||||
];
|
|
||||||
|
|
||||||
diag.span_label(
|
diag.span_label(
|
||||||
lifetime_ref.ident.span,
|
lifetime_ref.ident.span,
|
||||||
@ -1378,7 +1387,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||||||
Scope::Root { opt_parent_item } => {
|
Scope::Root { opt_parent_item } => {
|
||||||
if let Some(parent_item) = opt_parent_item
|
if let Some(parent_item) = opt_parent_item
|
||||||
&& let parent_generics = self.tcx.generics_of(parent_item)
|
&& let parent_generics = self.tcx.generics_of(parent_item)
|
||||||
&& parent_generics.param_def_id_to_index(self.tcx, param_def_id.to_def_id()).is_some()
|
&& parent_generics
|
||||||
|
.param_def_id_to_index(self.tcx, param_def_id.to_def_id())
|
||||||
|
.is_some()
|
||||||
{
|
{
|
||||||
break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id()));
|
break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id()));
|
||||||
}
|
}
|
||||||
@ -1689,14 +1700,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||||||
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
|
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
|
||||||
let bound_vars = if let Some(type_def_id) = type_def_id
|
let bound_vars = if let Some(type_def_id) = type_def_id
|
||||||
&& self.tcx.def_kind(type_def_id) == DefKind::Trait
|
&& self.tcx.def_kind(type_def_id) == DefKind::Trait
|
||||||
&& let Some((mut bound_vars, assoc_fn)) =
|
&& let Some((mut bound_vars, assoc_fn)) = BoundVarContext::supertrait_hrtb_vars(
|
||||||
BoundVarContext::supertrait_hrtb_vars(
|
self.tcx,
|
||||||
self.tcx,
|
type_def_id,
|
||||||
type_def_id,
|
binding.ident,
|
||||||
binding.ident,
|
ty::AssocKind::Fn,
|
||||||
ty::AssocKind::Fn,
|
) {
|
||||||
)
|
|
||||||
{
|
|
||||||
bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map(
|
bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map(
|
||||||
|param| match param.kind {
|
|param| match param.kind {
|
||||||
ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
|
ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
|
||||||
@ -1708,14 +1717,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||||||
ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
|
ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
bound_vars
|
bound_vars.extend(
|
||||||
.extend(self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars());
|
self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(),
|
||||||
|
);
|
||||||
bound_vars
|
bound_vars
|
||||||
} else {
|
} else {
|
||||||
self.tcx.sess.delay_span_bug(
|
self.tcx
|
||||||
binding.ident.span,
|
.sess
|
||||||
"bad return type notation here",
|
.delay_span_bug(binding.ident.span, "bad return type notation here");
|
||||||
);
|
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
self.with(scope, |this| {
|
self.with(scope, |this| {
|
||||||
|
@ -30,10 +30,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
|
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
|
||||||
if constant.hir_id() == hir_id =>
|
if constant.hir_id() == hir_id =>
|
||||||
{
|
{
|
||||||
return tcx.types.usize
|
return tcx.types.usize;
|
||||||
}
|
}
|
||||||
Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
|
Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
|
||||||
return tcx.typeck(def_id).node_type(e.hir_id)
|
return tcx.typeck(def_id).node_type(e.hir_id);
|
||||||
}
|
}
|
||||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||||
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
|
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
|
||||||
@ -43,36 +43,38 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}) =>
|
}) =>
|
||||||
{
|
{
|
||||||
return tcx.typeck(def_id).node_type(hir_id)
|
return tcx.typeck(def_id).node_type(hir_id);
|
||||||
}
|
}
|
||||||
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
|
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
|
||||||
return tcx
|
return tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx);
|
||||||
.adt_def(tcx.hir().get_parent_item(hir_id))
|
|
||||||
.repr()
|
|
||||||
.discr_type()
|
|
||||||
.to_ty(tcx)
|
|
||||||
}
|
}
|
||||||
Node::GenericParam(&GenericParam {
|
Node::GenericParam(&GenericParam {
|
||||||
def_id: param_def_id,
|
def_id: param_def_id,
|
||||||
kind: GenericParamKind::Const { default: Some(ct), .. },
|
kind: GenericParamKind::Const { default: Some(ct), .. },
|
||||||
..
|
..
|
||||||
}) if ct.hir_id == hir_id => {
|
}) if ct.hir_id == hir_id => {
|
||||||
return tcx.type_of(param_def_id)
|
return tcx
|
||||||
|
.type_of(param_def_id)
|
||||||
.no_bound_vars()
|
.no_bound_vars()
|
||||||
.expect("const parameter types cannot be generic")
|
.expect("const parameter types cannot be generic");
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
|
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
|
||||||
if let Node::TraitRef(trait_ref) = tcx.hir().get(
|
if let Node::TraitRef(trait_ref) = tcx.hir().get(tcx.hir().parent_id(binding_id)) =>
|
||||||
tcx.hir().parent_id(binding_id)
|
|
||||||
) =>
|
|
||||||
{
|
{
|
||||||
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
||||||
return Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find trait");
|
return Ty::new_error_with_message(
|
||||||
|
tcx,
|
||||||
|
tcx.def_span(def_id),
|
||||||
|
"Could not find trait",
|
||||||
|
);
|
||||||
};
|
};
|
||||||
let assoc_items = tcx.associated_items(trait_def_id);
|
let assoc_items = tcx.associated_items(trait_def_id);
|
||||||
let assoc_item = assoc_items.find_by_name_and_kind(
|
let assoc_item = assoc_items.find_by_name_and_kind(
|
||||||
tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(),
|
tcx,
|
||||||
|
binding.ident,
|
||||||
|
ty::AssocKind::Const,
|
||||||
|
def_id.to_def_id(),
|
||||||
);
|
);
|
||||||
return if let Some(assoc_item) = assoc_item {
|
return if let Some(assoc_item) = assoc_item {
|
||||||
tcx.type_of(assoc_item.def_id)
|
tcx.type_of(assoc_item.def_id)
|
||||||
@ -80,8 +82,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
.expect("const parameter types cannot be generic")
|
.expect("const parameter types cannot be generic")
|
||||||
} else {
|
} else {
|
||||||
// FIXME(associated_const_equality): add a useful error message here.
|
// FIXME(associated_const_equality): add a useful error message here.
|
||||||
Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find associated const on trait")
|
Ty::new_error_with_message(
|
||||||
}
|
tcx,
|
||||||
|
tcx.def_span(def_id),
|
||||||
|
"Could not find associated const on trait",
|
||||||
|
)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This match arm is for when the def_id appears in a GAT whose
|
// This match arm is for when the def_id appears in a GAT whose
|
||||||
@ -138,7 +144,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
(generics, arg_index)
|
(generics, arg_index)
|
||||||
} else {
|
} else {
|
||||||
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
|
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
|
||||||
return Ty::new_error_with_message(tcx,
|
return Ty::new_error_with_message(
|
||||||
|
tcx,
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
"unexpected non-GAT usage of an anon const",
|
"unexpected non-GAT usage of an anon const",
|
||||||
);
|
);
|
||||||
@ -155,7 +162,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
// As there is no relevant param for `def_id`, we simply return
|
// As there is no relevant param for `def_id`, we simply return
|
||||||
// `None` here.
|
// `None` here.
|
||||||
let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
|
let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
|
||||||
return Ty::new_error_with_message(tcx,
|
return Ty::new_error_with_message(
|
||||||
|
tcx,
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
format!("unable to find type-dependent def for {parent_node_id:?}"),
|
format!("unable to find type-dependent def for {parent_node_id:?}"),
|
||||||
);
|
);
|
||||||
@ -196,14 +204,16 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
|
if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
|
||||||
path
|
path
|
||||||
} else {
|
} else {
|
||||||
return Ty::new_error_with_message(tcx,
|
return Ty::new_error_with_message(
|
||||||
|
tcx,
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
format!("unable to find const parent for {hir_id} in pat {pat:?}"),
|
format!("unable to find const parent for {hir_id} in pat {pat:?}"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Ty::new_error_with_message(tcx,
|
return Ty::new_error_with_message(
|
||||||
|
tcx,
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
format!("unexpected const parent path {parent_node:?}"),
|
format!("unexpected const parent path {parent_node:?}"),
|
||||||
);
|
);
|
||||||
@ -216,16 +226,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
|
let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
|
||||||
let args = seg.args?;
|
let args = seg.args?;
|
||||||
args.args
|
args.args
|
||||||
.iter()
|
|
||||||
.filter(|arg| arg.is_ty_or_const())
|
|
||||||
.position(|arg| arg.hir_id() == hir_id)
|
|
||||||
.map(|index| (index, seg)).or_else(|| args.bindings
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(TypeBinding::opt_const)
|
.filter(|arg| arg.is_ty_or_const())
|
||||||
.position(|ct| ct.hir_id == hir_id)
|
.position(|arg| arg.hir_id() == hir_id)
|
||||||
.map(|idx| (idx, seg)))
|
.map(|index| (index, seg))
|
||||||
|
.or_else(|| {
|
||||||
|
args.bindings
|
||||||
|
.iter()
|
||||||
|
.filter_map(TypeBinding::opt_const)
|
||||||
|
.position(|ct| ct.hir_id == hir_id)
|
||||||
|
.map(|idx| (idx, seg))
|
||||||
|
})
|
||||||
}) else {
|
}) else {
|
||||||
return Ty::new_error_with_message(tcx,
|
return Ty::new_error_with_message(
|
||||||
|
tcx,
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
"no arg matching AnonConst in path",
|
"no arg matching AnonConst in path",
|
||||||
);
|
);
|
||||||
@ -234,7 +248,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
let generics = match tcx.res_generics_def_id(segment.res) {
|
let generics = match tcx.res_generics_def_id(segment.res) {
|
||||||
Some(def_id) => tcx.generics_of(def_id),
|
Some(def_id) => tcx.generics_of(def_id),
|
||||||
None => {
|
None => {
|
||||||
return Ty::new_error_with_message(tcx,
|
return Ty::new_error_with_message(
|
||||||
|
tcx,
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
|
format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
|
||||||
);
|
);
|
||||||
@ -244,10 +259,13 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||||||
(generics, arg_index)
|
(generics, arg_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => return Ty::new_error_with_message(tcx,
|
_ => {
|
||||||
tcx.def_span(def_id),
|
return Ty::new_error_with_message(
|
||||||
format!("unexpected const parent in type_of(): {parent_node:?}"),
|
tcx,
|
||||||
),
|
tcx.def_span(def_id),
|
||||||
|
format!("unexpected const parent in type_of(): {parent_node:?}"),
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(?parent_node);
|
debug!(?parent_node);
|
||||||
|
@ -226,7 +226,9 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
|
|||||||
let mut suggested = false;
|
let mut suggested = false;
|
||||||
// Don't suggest setting the type params if there are some already: the order is
|
// Don't suggest setting the type params if there are some already: the order is
|
||||||
// tricky to get right and the user will already know what the syntax is.
|
// tricky to get right and the user will already know what the syntax is.
|
||||||
if let Some(snippet) = self.span_snippet && self.empty_generic_args {
|
if let Some(snippet) = self.span_snippet
|
||||||
|
&& self.empty_generic_args
|
||||||
|
{
|
||||||
if snippet.ends_with('>') {
|
if snippet.ends_with('>') {
|
||||||
// The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
|
// The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
|
||||||
// we would have to preserve the right order. For now, as clearly the user is
|
// we would have to preserve the right order. For now, as clearly the user is
|
||||||
|
@ -131,7 +131,9 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
|
fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
|
||||||
if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() {
|
if let Node::Impl(impl2_id) = impl2_node
|
||||||
|
&& tcx.associated_item_def_ids(impl1_def_id).is_empty()
|
||||||
|
{
|
||||||
let base_impl_span = tcx.def_span(impl2_id);
|
let base_impl_span = tcx.def_span(impl2_id);
|
||||||
tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span });
|
tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span });
|
||||||
}
|
}
|
||||||
|
@ -316,12 +316,18 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Suggest `'_` when in function parameter or elided function return.
|
// Suggest `'_` when in function parameter or elided function return.
|
||||||
if let Some(fn_decl) = node.fn_decl() && let Some(ty_id) = ty_id {
|
if let Some(fn_decl) = node.fn_decl()
|
||||||
|
&& let Some(ty_id) = ty_id
|
||||||
|
{
|
||||||
let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id);
|
let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id);
|
||||||
let in_ret = matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id);
|
let in_ret =
|
||||||
|
matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id);
|
||||||
|
|
||||||
if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) {
|
if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) {
|
||||||
return std::iter::repeat("'_".to_owned()).take(num_params_to_take).collect::<Vec<_>>().join(", ");
|
return std::iter::repeat("'_".to_owned())
|
||||||
|
.take(num_params_to_take)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,28 +736,27 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
|
if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
|
||||||
&& let Some(parent_node) = self.tcx.hir().find(parent_node)
|
&& let Some(parent_node) = self.tcx.hir().find(parent_node)
|
||||||
&& let hir::Node::Expr(expr) = parent_node {
|
&& let hir::Node::Expr(expr) = parent_node
|
||||||
|
{
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
hir::ExprKind::Path(qpath) => {
|
hir::ExprKind::Path(qpath) => self
|
||||||
self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
|
.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
|
||||||
err,
|
err,
|
||||||
qpath,
|
qpath,
|
||||||
msg,
|
msg,
|
||||||
num_assoc_fn_excess_args,
|
num_assoc_fn_excess_args,
|
||||||
num_trait_generics_except_self
|
num_trait_generics_except_self,
|
||||||
)
|
),
|
||||||
},
|
hir::ExprKind::MethodCall(..) => self
|
||||||
hir::ExprKind::MethodCall(..) => {
|
.suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
|
||||||
self.suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
|
|
||||||
err,
|
err,
|
||||||
trait_,
|
trait_,
|
||||||
expr,
|
expr,
|
||||||
msg,
|
msg,
|
||||||
num_assoc_fn_excess_args,
|
num_assoc_fn_excess_args,
|
||||||
num_trait_generics_except_self
|
num_trait_generics_except_self,
|
||||||
)
|
),
|
||||||
},
|
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -766,23 +771,25 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||||||
num_trait_generics_except_self: usize,
|
num_trait_generics_except_self: usize,
|
||||||
) {
|
) {
|
||||||
if let hir::QPath::Resolved(_, path) = qpath
|
if let hir::QPath::Resolved(_, path) = qpath
|
||||||
&& let Some(trait_path_segment) = path.segments.get(0) {
|
&& let Some(trait_path_segment) = path.segments.get(0)
|
||||||
|
{
|
||||||
let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params();
|
let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params();
|
||||||
|
|
||||||
if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args == num_trait_generics_except_self
|
if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args
|
||||||
|
== num_trait_generics_except_self
|
||||||
{
|
{
|
||||||
if let Some(span) = self.gen_args.span_ext()
|
if let Some(span) = self.gen_args.span_ext()
|
||||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||||
|
{
|
||||||
let sugg = vec![
|
let sugg = vec![
|
||||||
(self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)),
|
(
|
||||||
(span.with_lo(self.path_segment.ident.span.hi()), "".to_owned())
|
self.path_segment.ident.span,
|
||||||
|
format!("{}::{}", snippet, self.path_segment.ident),
|
||||||
|
),
|
||||||
|
(span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()),
|
||||||
];
|
];
|
||||||
|
|
||||||
err.multipart_suggestion(
|
err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
|
||||||
msg,
|
|
||||||
sugg,
|
|
||||||
Applicability::MaybeIncorrect
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,7 +373,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// 6 | | };
|
// 6 | | };
|
||||||
// | |_____^ expected integer, found `()`
|
// | |_____^ expected integer, found `()`
|
||||||
// ```
|
// ```
|
||||||
if block.expr.is_none() && block.stmts.is_empty()
|
if block.expr.is_none()
|
||||||
|
&& block.stmts.is_empty()
|
||||||
&& let Some(outer_span) = &mut outer_span
|
&& let Some(outer_span) = &mut outer_span
|
||||||
&& let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span)
|
&& let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span)
|
||||||
{
|
{
|
||||||
|
@ -421,13 +421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
|
.steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
|
||||||
{
|
{
|
||||||
// Try suggesting `foo(a)` -> `a.foo()` if possible.
|
// Try suggesting `foo(a)` -> `a.foo()` if possible.
|
||||||
self.suggest_call_as_method(
|
self.suggest_call_as_method(&mut diag, segment, arg_exprs, call_expr, expected);
|
||||||
&mut diag,
|
|
||||||
segment,
|
|
||||||
arg_exprs,
|
|
||||||
call_expr,
|
|
||||||
expected
|
|
||||||
);
|
|
||||||
diag.emit();
|
diag.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,50 +373,49 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||||||
let mut sugg_mutref = false;
|
let mut sugg_mutref = false;
|
||||||
if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
|
if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
|
||||||
if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind()
|
if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind()
|
||||||
&& fcx
|
&& fcx.can_coerce(
|
||||||
.can_coerce(
|
Ty::new_ref(
|
||||||
Ty::new_ref(fcx.tcx,
|
fcx.tcx,
|
||||||
fcx.tcx.lifetimes.re_erased,
|
fcx.tcx.lifetimes.re_erased,
|
||||||
TypeAndMut { ty: expr_ty, mutbl },
|
TypeAndMut { ty: expr_ty, mutbl },
|
||||||
),
|
),
|
||||||
self.cast_ty,
|
self.cast_ty,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty));
|
sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty));
|
||||||
} else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind()
|
} else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind()
|
||||||
&& expr_mutbl == Mutability::Not
|
&& expr_mutbl == Mutability::Not
|
||||||
&& mutbl == Mutability::Mut
|
&& mutbl == Mutability::Mut
|
||||||
&& fcx
|
&& fcx.can_coerce(
|
||||||
.can_coerce(
|
Ty::new_ref(
|
||||||
Ty::new_ref(fcx.tcx,
|
fcx.tcx,
|
||||||
expr_reg,
|
expr_reg,
|
||||||
TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
|
TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
|
||||||
),
|
),
|
||||||
self.cast_ty,
|
self.cast_ty,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
sugg_mutref = true;
|
sugg_mutref = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sugg_mutref
|
if !sugg_mutref
|
||||||
&& sugg == None
|
&& sugg == None
|
||||||
&& fcx
|
&& fcx.can_coerce(
|
||||||
.can_coerce(
|
Ty::new_ref(fcx.tcx, reg, TypeAndMut { ty: self.expr_ty, mutbl }),
|
||||||
Ty::new_ref(fcx.tcx,reg, TypeAndMut { ty: self.expr_ty, mutbl }),
|
self.cast_ty,
|
||||||
self.cast_ty,
|
)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
sugg = Some((format!("&{}", mutbl.prefix_str()), false));
|
sugg = Some((format!("&{}", mutbl.prefix_str()), false));
|
||||||
}
|
}
|
||||||
} else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind()
|
} else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind()
|
||||||
&& fcx
|
&& fcx.can_coerce(
|
||||||
.can_coerce(
|
Ty::new_ref(
|
||||||
Ty::new_ref(fcx.tcx,
|
fcx.tcx,
|
||||||
fcx.tcx.lifetimes.re_erased,
|
fcx.tcx.lifetimes.re_erased,
|
||||||
TypeAndMut { ty: self.expr_ty, mutbl },
|
TypeAndMut { ty: self.expr_ty, mutbl },
|
||||||
),
|
),
|
||||||
self.cast_ty,
|
self.cast_ty,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
sugg = Some((format!("&{}", mutbl.prefix_str()), false));
|
sugg = Some((format!("&{}", mutbl.prefix_str()), false));
|
||||||
}
|
}
|
||||||
@ -942,10 +941,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||||||
lint::builtin::CENUM_IMPL_DROP_CAST,
|
lint::builtin::CENUM_IMPL_DROP_CAST,
|
||||||
self.expr.hir_id,
|
self.expr.hir_id,
|
||||||
self.span,
|
self.span,
|
||||||
errors::CastEnumDrop {
|
errors::CastEnumDrop { expr_ty, cast_ty },
|
||||||
expr_ty,
|
|
||||||
cast_ty,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,18 +55,22 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
|
|
||||||
fn_maybe_err(tcx, span, fn_sig.abi);
|
fn_maybe_err(tcx, span, fn_sig.abi);
|
||||||
|
|
||||||
if let Some(kind) = body.generator_kind && can_be_generator.is_some() {
|
if let Some(kind) = body.generator_kind
|
||||||
|
&& can_be_generator.is_some()
|
||||||
|
{
|
||||||
let yield_ty = if kind == hir::GeneratorKind::Gen {
|
let yield_ty = if kind == hir::GeneratorKind::Gen {
|
||||||
let yield_ty = fcx
|
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
|
||||||
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
|
kind: TypeVariableOriginKind::TypeInference,
|
||||||
|
span,
|
||||||
|
});
|
||||||
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
|
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
|
||||||
yield_ty
|
yield_ty
|
||||||
} else {
|
} else {
|
||||||
Ty::new_unit(tcx,)
|
Ty::new_unit(tcx)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resume type defaults to `()` if the generator has no argument.
|
// Resume type defaults to `()` if the generator has no argument.
|
||||||
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx,));
|
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx));
|
||||||
|
|
||||||
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
|
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
|
||||||
}
|
}
|
||||||
@ -173,7 +177,9 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig);
|
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() {
|
if let Some(lang_start_defid) = tcx.lang_items().start_fn()
|
||||||
|
&& lang_start_defid == fn_def_id.to_def_id()
|
||||||
|
{
|
||||||
check_lang_start_fn(tcx, fn_sig, fn_def_id);
|
check_lang_start_fn(tcx, fn_sig, fn_def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +228,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// Given a Projection predicate, we can potentially infer
|
// Given a Projection predicate, we can potentially infer
|
||||||
// the complete signature.
|
// the complete signature.
|
||||||
if expected_sig.is_none()
|
if expected_sig.is_none()
|
||||||
&& let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = bound_predicate.skip_binder()
|
&& let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) =
|
||||||
|
bound_predicate.skip_binder()
|
||||||
{
|
{
|
||||||
let inferred_sig = self.normalize(
|
let inferred_sig = self.normalize(
|
||||||
span,
|
span,
|
||||||
|
@ -1619,8 +1619,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||||
}
|
}
|
||||||
if let Some(expression) = expression
|
if let Some(expression) = expression
|
||||||
&& let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
|
&& let hir::ExprKind::Loop(loop_blk, ..) = expression.kind
|
||||||
intravisit::walk_block(& mut visitor, loop_blk);
|
{
|
||||||
|
intravisit::walk_block(&mut visitor, loop_blk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObligationCauseCode::ReturnValue(id) => {
|
ObligationCauseCode::ReturnValue(id) => {
|
||||||
@ -1661,7 +1662,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if visitor.ret_exprs.len() > 0 && let Some(expr) = expression {
|
if visitor.ret_exprs.len() > 0
|
||||||
|
&& let Some(expr) = expression
|
||||||
|
{
|
||||||
self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
|
self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1723,7 +1726,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||||||
let parent_id = fcx.tcx.hir().parent_id(id);
|
let parent_id = fcx.tcx.hir().parent_id(id);
|
||||||
let parent = fcx.tcx.hir().get(parent_id);
|
let parent = fcx.tcx.hir().get(parent_id);
|
||||||
if let Some(expr) = expression
|
if let Some(expr) = expression
|
||||||
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent
|
&& let hir::Node::Expr(hir::Expr {
|
||||||
|
kind: hir::ExprKind::Closure(&hir::Closure { body, .. }),
|
||||||
|
..
|
||||||
|
}) = parent
|
||||||
&& !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..))
|
&& !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..))
|
||||||
{
|
{
|
||||||
fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
|
fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
|
||||||
@ -1798,12 +1804,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||||||
&& let Some(fn_sig) = fcx.body_fn_sig()
|
&& let Some(fn_sig) = fcx.body_fn_sig()
|
||||||
&& fn_sig.output().is_ty_var()
|
&& fn_sig.output().is_ty_var()
|
||||||
{
|
{
|
||||||
err.span_note(
|
err.span_note(sp, format!("return type inferred to be `{expected}` here"));
|
||||||
sp,
|
|
||||||
format!(
|
|
||||||
"return type inferred to be `{expected}` here"
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err
|
err
|
||||||
|
@ -151,7 +151,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&& let [segment] = path.segments
|
&& let [segment] = path.segments
|
||||||
&& segment.ident.name.as_str() == name
|
&& segment.ident.name.as_str() == name
|
||||||
&& let Res::Local(hir_id) = path.res
|
&& let Res::Local(hir_id) = path.res
|
||||||
&& let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2)
|
&& let Some((_, hir::Node::Expr(match_expr))) =
|
||||||
|
self.tcx.hir().parent_iter(hir_id).nth(2)
|
||||||
&& let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
|
&& let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
|
||||||
&& let hir::ExprKind::Tup(exprs) = scrutinee.kind
|
&& let hir::ExprKind::Tup(exprs) = scrutinee.kind
|
||||||
&& let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
|
&& let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
|
||||||
@ -450,20 +451,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// If our binding became incompatible while it was a receiver
|
// If our binding became incompatible while it was a receiver
|
||||||
// to a method call, we may be able to make a better guess to
|
// to a method call, we may be able to make a better guess to
|
||||||
// the source of a type mismatch.
|
// the source of a type mismatch.
|
||||||
let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; };
|
let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
|
let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
|
||||||
let Ok(method) =
|
let Ok(method) = self.lookup_method_for_diagnostic(
|
||||||
self.lookup_method_for_diagnostic(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr)
|
rcvr_ty,
|
||||||
else {
|
segment,
|
||||||
|
DUMMY_SP,
|
||||||
|
parent_expr,
|
||||||
|
rcvr,
|
||||||
|
) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
|
let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
|
||||||
let ideal_method = self
|
let ideal_method = self
|
||||||
.lookup_method_for_diagnostic(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr)
|
.lookup_method_for_diagnostic(
|
||||||
|
ideal_rcvr_ty,
|
||||||
|
segment,
|
||||||
|
DUMMY_SP,
|
||||||
|
parent_expr,
|
||||||
|
rcvr,
|
||||||
|
)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|method| {
|
.and_then(|method| {
|
||||||
let _ = self.at(&ObligationCause::dummy(), self.param_env)
|
let _ = self
|
||||||
|
.at(&ObligationCause::dummy(), self.param_env)
|
||||||
.eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty)
|
.eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
Some(method)
|
Some(method)
|
||||||
@ -474,15 +488,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
for (idx, (expected_arg_ty, arg_expr)) in
|
for (idx, (expected_arg_ty, arg_expr)) in
|
||||||
std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
|
std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
|
||||||
{
|
{
|
||||||
let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; };
|
let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let arg_ty = arg_ty.fold_with(&mut fudger);
|
let arg_ty = arg_ty.fold_with(&mut fudger);
|
||||||
let _ = self.coerce(
|
let _ =
|
||||||
arg_expr,
|
self.coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None);
|
||||||
arg_ty,
|
|
||||||
*expected_arg_ty,
|
|
||||||
AllowTwoPhase::No,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
self.select_obligations_where_possible(|errs| {
|
self.select_obligations_where_possible(|errs| {
|
||||||
// Yeet the errors, we're already reporting errors.
|
// Yeet the errors, we're already reporting errors.
|
||||||
errs.clear();
|
errs.clear();
|
||||||
@ -648,10 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
None => self.tcx.types.unit,
|
None => self.tcx.types.unit,
|
||||||
};
|
};
|
||||||
if self.can_eq(self.param_env, ty, expected) {
|
if self.can_eq(self.param_env, ty, expected) {
|
||||||
err.span_label(
|
err.span_label(ex.span, "expected because of this `break`");
|
||||||
ex.span,
|
|
||||||
"expected because of this `break`",
|
|
||||||
);
|
|
||||||
exit = true;
|
exit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1410,10 +1418,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
let bind = self.tcx.hir().find(*bind_hir_id);
|
let bind = self.tcx.hir().find(*bind_hir_id);
|
||||||
let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id));
|
let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id));
|
||||||
if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. })) = bind &&
|
if let Some(hir::Node::Pat(hir::Pat {
|
||||||
let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent {
|
kind: hir::PatKind::Binding(_, _hir_id, _, _),
|
||||||
return true;
|
..
|
||||||
}
|
})) = bind
|
||||||
|
&& let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1507,10 +1519,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// ```
|
// ```
|
||||||
let ref_ty = match mutability {
|
let ref_ty = match mutability {
|
||||||
hir::Mutability::Mut => {
|
hir::Mutability::Mut => {
|
||||||
Ty::new_mut_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty)
|
Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
|
||||||
}
|
}
|
||||||
hir::Mutability::Not => {
|
hir::Mutability::Not => {
|
||||||
Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty)
|
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if self.can_coerce(ref_ty, expected) {
|
if self.can_coerce(ref_ty, expected) {
|
||||||
@ -1566,7 +1578,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
|
let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr)
|
||||||
|
{
|
||||||
Some(ident) => format!("{ident}: "),
|
Some(ident) => format!("{ident}: "),
|
||||||
None => String::new(),
|
None => String::new(),
|
||||||
};
|
};
|
||||||
@ -1611,8 +1624,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let make_sugg = |start: Span, end: BytePos| {
|
let make_sugg = |start: Span, end: BytePos| {
|
||||||
// skip `(` for tuples such as `(c) = (&123)`.
|
// skip `(` for tuples such as `(c) = (&123)`.
|
||||||
// make sure we won't suggest like `(c) = 123)` which is incorrect.
|
// make sure we won't suggest like `(c) = 123)` which is incorrect.
|
||||||
let sp = sm.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
|
let sp = sm
|
||||||
.map_or(start, |s| s.shrink_to_hi());
|
.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
|
||||||
|
.map_or(start, |s| s.shrink_to_hi());
|
||||||
Some((
|
Some((
|
||||||
vec![(sp.with_hi(end), String::new())],
|
vec![(sp.with_hi(end), String::new())],
|
||||||
"consider removing the borrow".to_string(),
|
"consider removing the borrow".to_string(),
|
||||||
@ -1635,12 +1649,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.find(|&s| sp.contains(s))
|
.find(|&s| sp.contains(s))
|
||||||
&& sm.is_span_accessible(call_span)
|
&& sm.is_span_accessible(call_span)
|
||||||
{
|
{
|
||||||
return make_sugg(sp, call_span.lo())
|
return make_sugg(sp, call_span.lo());
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
|
if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
|
||||||
return make_sugg(sp, expr.span.lo())
|
return make_sugg(sp, expr.span.lo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
@ -1760,10 +1774,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
|
let prefix =
|
||||||
Some(ident) => format!("{ident}: "),
|
match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
|
||||||
None => String::new(),
|
Some(ident) => format!("{ident}: "),
|
||||||
};
|
None => String::new(),
|
||||||
|
};
|
||||||
|
|
||||||
let (span, suggestion) = if self.is_else_if_block(expr) {
|
let (span, suggestion) = if self.is_else_if_block(expr) {
|
||||||
// Don't suggest nonsense like `else *if`
|
// Don't suggest nonsense like `else *if`
|
||||||
|
@ -717,7 +717,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// ... except when we try to 'break rust;'.
|
// ... except when we try to 'break rust;'.
|
||||||
// ICE this expression in particular (see #43162).
|
// ICE this expression in particular (see #43162).
|
||||||
if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind {
|
if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind {
|
||||||
if let [segment] = path.segments && segment.ident.name == sym::rust {
|
if let [segment] = path.segments
|
||||||
|
&& segment.ident.name == sym::rust
|
||||||
|
{
|
||||||
fatally_break_rust(self.tcx);
|
fatally_break_rust(self.tcx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -826,7 +828,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&& let ExprKind::Block(body, _) = return_expr.kind
|
&& let ExprKind::Block(body, _) = return_expr.kind
|
||||||
&& let Some(last_expr) = body.expr
|
&& let Some(last_expr) = body.expr
|
||||||
{
|
{
|
||||||
span = last_expr.span;
|
span = last_expr.span;
|
||||||
}
|
}
|
||||||
ret_coercion.borrow_mut().coerce(
|
ret_coercion.borrow_mut().coerce(
|
||||||
self,
|
self,
|
||||||
@ -841,7 +843,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// Point any obligations that were registered due to opaque type
|
// Point any obligations that were registered due to opaque type
|
||||||
// inference at the return expression.
|
// inference at the return expression.
|
||||||
self.select_obligations_where_possible(|errors| {
|
self.select_obligations_where_possible(|errors| {
|
||||||
self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty, return_expr.span);
|
self.point_at_return_for_opaque_ty_error(
|
||||||
|
errors,
|
||||||
|
span,
|
||||||
|
return_expr_ty,
|
||||||
|
return_expr.span,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1402,7 +1409,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
|
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
|
||||||
&& let Some(span) = self.tcx.hir().opt_span(hir_id)
|
&& let Some(span) = self.tcx.hir().opt_span(hir_id)
|
||||||
{
|
{
|
||||||
match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) {
|
match self
|
||||||
|
.tcx
|
||||||
|
.sess
|
||||||
|
.diagnostic()
|
||||||
|
.steal_diagnostic(span, StashKey::UnderscoreForArrayLengths)
|
||||||
|
{
|
||||||
Some(mut err) => {
|
Some(mut err) => {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
span,
|
span,
|
||||||
@ -1412,7 +1424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
None => ()
|
None => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1931,11 +1943,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
) {
|
) {
|
||||||
// I don't use 'is_range_literal' because only double-sided, half-open ranges count.
|
// I don't use 'is_range_literal' because only double-sided, half-open ranges count.
|
||||||
if let ExprKind::Struct(
|
if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [range_start, range_end], _) =
|
||||||
QPath::LangItem(LangItem::Range, ..),
|
last_expr_field.expr.kind
|
||||||
[range_start, range_end],
|
|
||||||
_,
|
|
||||||
) = last_expr_field.expr.kind
|
|
||||||
&& let variant_field =
|
&& let variant_field =
|
||||||
variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
|
variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
|
||||||
&& let range_def_id = self.tcx.lang_items().range_struct()
|
&& let range_def_id = self.tcx.lang_items().range_struct()
|
||||||
@ -1970,13 +1979,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.sess
|
.sess
|
||||||
.source_map()
|
.source_map()
|
||||||
.span_extend_while(range_start.span, |c| c.is_whitespace())
|
.span_extend_while(range_start.span, |c| c.is_whitespace())
|
||||||
.unwrap_or(range_start.span).shrink_to_hi().to(range_end.span);
|
.unwrap_or(range_start.span)
|
||||||
|
.shrink_to_hi()
|
||||||
|
.to(range_end.span);
|
||||||
|
|
||||||
err.subdiagnostic(TypeMismatchFruTypo {
|
err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr });
|
||||||
expr_span: range_start.span,
|
|
||||||
fru_span,
|
|
||||||
expr,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2293,7 +2300,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
Some('e') | Some('E') => {
|
Some('e') | Some('E') => {
|
||||||
chars.next();
|
chars.next();
|
||||||
if let Some(c) = chars.peek()
|
if let Some(c) = chars.peek()
|
||||||
&& !c.is_numeric() && *c != '-' && *c != '+'
|
&& !c.is_numeric()
|
||||||
|
&& *c != '-'
|
||||||
|
&& *c != '+'
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2421,7 +2430,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.suggest_fn_call(&mut err, base, base_ty, |output_ty| {
|
self.suggest_fn_call(&mut err, base, base_ty, |output_ty| {
|
||||||
if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() {
|
if let ty::Adt(def, _) = output_ty.kind()
|
||||||
|
&& !def.is_enum()
|
||||||
|
{
|
||||||
def.non_enum_variant().fields.iter().any(|field| {
|
def.non_enum_variant().fields.iter().any(|field| {
|
||||||
field.ident(self.tcx) == ident
|
field.ident(self.tcx) == ident
|
||||||
&& field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
|
&& field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
|
||||||
@ -2842,9 +2853,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// fixed expression:
|
// fixed expression:
|
||||||
if let ExprKind::Lit(ref lit) = idx.kind
|
if let ExprKind::Lit(ref lit) = idx.kind
|
||||||
&& let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node
|
&& let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node
|
||||||
&& i < types.len().try_into().expect("expected tuple index to be < usize length")
|
&& i < types
|
||||||
|
.len()
|
||||||
|
.try_into()
|
||||||
|
.expect("expected tuple index to be < usize length")
|
||||||
{
|
{
|
||||||
|
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
brackets_span,
|
brackets_span,
|
||||||
"to access tuple elements, use",
|
"to access tuple elements, use",
|
||||||
@ -2853,7 +2866,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
needs_note = false;
|
needs_note = false;
|
||||||
} else if let ExprKind::Path(..) = idx.peel_borrows().kind {
|
} else if let ExprKind::Path(..) = idx.peel_borrows().kind {
|
||||||
err.span_label(idx.span, "cannot access tuple elements at a variable index");
|
err.span_label(
|
||||||
|
idx.span,
|
||||||
|
"cannot access tuple elements at a variable index",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if needs_note {
|
if needs_note {
|
||||||
err.help(
|
err.help(
|
||||||
|
@ -142,7 +142,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||||||
// type, `?T` is not considered unsolved, but `?I` is. The
|
// type, `?T` is not considered unsolved, but `?I` is. The
|
||||||
// same is true for float variables.)
|
// same is true for float variables.)
|
||||||
let fallback = match ty.kind() {
|
let fallback = match ty.kind() {
|
||||||
_ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e),
|
_ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e),
|
||||||
ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
|
ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
|
||||||
ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
|
ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
|
||||||
_ => match diverging_fallback.get(&ty) {
|
_ => match diverging_fallback.get(&ty) {
|
||||||
|
@ -445,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
|
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
|
||||||
match self.typeck_results.borrow().node_types().get(id) {
|
match self.typeck_results.borrow().node_types().get(id) {
|
||||||
Some(&t) => t,
|
Some(&t) => t,
|
||||||
None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e),
|
None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e),
|
||||||
None => {
|
None => {
|
||||||
bug!(
|
bug!(
|
||||||
"no type for node {} in fcx {}",
|
"no type for node {} in fcx {}",
|
||||||
@ -459,7 +459,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
|
pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
|
||||||
match self.typeck_results.borrow().node_types().get(id) {
|
match self.typeck_results.borrow().node_types().get(id) {
|
||||||
Some(&t) => Some(t),
|
Some(&t) => Some(t),
|
||||||
None if let Some(e) = self.tainted_by_errors() => Some(Ty::new_error(self.tcx,e)),
|
None if let Some(e) = self.tainted_by_errors() => Some(Ty::new_error(self.tcx, e)),
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -713,7 +713,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if let ty::GenericArgKind::Type(ty) = ty.unpack()
|
if let ty::GenericArgKind::Type(ty) = ty.unpack()
|
||||||
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
|
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
|
||||||
&& let Some(def_id) = def_id.as_local()
|
&& let Some(def_id) = def_id.as_local()
|
||||||
&& self.opaque_type_origin(def_id).is_some() {
|
&& self.opaque_type_origin(def_id).is_some()
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -833,7 +834,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
|
.resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
|
||||||
.and_then(|r| {
|
.and_then(|r| {
|
||||||
// lint bare trait if the method is found in the trait
|
// lint bare trait if the method is found in the trait
|
||||||
if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
|
if span.edition().at_least_rust_2021()
|
||||||
|
&& let Some(mut diag) = self
|
||||||
|
.tcx
|
||||||
|
.sess
|
||||||
|
.diagnostic()
|
||||||
|
.steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
|
||||||
|
{
|
||||||
diag.emit();
|
diag.emit();
|
||||||
}
|
}
|
||||||
Ok(r)
|
Ok(r)
|
||||||
@ -863,7 +870,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// emit or cancel the diagnostic for bare traits
|
// emit or cancel the diagnostic for bare traits
|
||||||
if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
|
if span.edition().at_least_rust_2021()
|
||||||
|
&& let Some(mut diag) = self
|
||||||
|
.tcx
|
||||||
|
.sess
|
||||||
|
.diagnostic()
|
||||||
|
.steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
|
||||||
|
{
|
||||||
if trait_missing_method {
|
if trait_missing_method {
|
||||||
// cancel the diag for bare traits when meeting `MyTrait::missing_method`
|
// cancel the diag for bare traits when meeting `MyTrait::missing_method`
|
||||||
diag.cancel();
|
diag.cancel();
|
||||||
@ -949,12 +962,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||||
owner_id,
|
owner_id,
|
||||||
..
|
..
|
||||||
})) = self.tcx.hir().find_parent(hir_id) => Some((
|
})) = self.tcx.hir().find_parent(hir_id) =>
|
||||||
hir::HirId::make_owner(owner_id.def_id),
|
{
|
||||||
&sig.decl,
|
Some((
|
||||||
ident,
|
hir::HirId::make_owner(owner_id.def_id),
|
||||||
ident.name != sym::main,
|
&sig.decl,
|
||||||
)),
|
ident,
|
||||||
|
ident.name != sym::main,
|
||||||
|
))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1077,11 +1093,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let mut user_self_ty = None;
|
let mut user_self_ty = None;
|
||||||
let mut is_alias_variant_ctor = false;
|
let mut is_alias_variant_ctor = false;
|
||||||
match res {
|
match res {
|
||||||
Res::Def(DefKind::Ctor(CtorOf::Variant, _), _)
|
Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) if let Some(self_ty) = self_ty => {
|
||||||
if let Some(self_ty) = self_ty =>
|
|
||||||
{
|
|
||||||
let adt_def = self_ty.normalized.ty_adt_def().unwrap();
|
let adt_def = self_ty.normalized.ty_adt_def().unwrap();
|
||||||
user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw });
|
user_self_ty =
|
||||||
|
Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw });
|
||||||
is_alias_variant_ctor = true;
|
is_alias_variant_ctor = true;
|
||||||
}
|
}
|
||||||
Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
|
Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
|
||||||
@ -1090,9 +1105,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let container_id = assoc_item.container_id(tcx);
|
let container_id = assoc_item.container_id(tcx);
|
||||||
debug!(?def_id, ?container, ?container_id);
|
debug!(?def_id, ?container, ?container_id);
|
||||||
match container {
|
match container {
|
||||||
ty::TraitContainer => {
|
ty::TraitContainer => callee::check_legal_trait_for_method_call(
|
||||||
callee::check_legal_trait_for_method_call(tcx, span, None, span, container_id)
|
tcx,
|
||||||
}
|
span,
|
||||||
|
None,
|
||||||
|
span,
|
||||||
|
container_id,
|
||||||
|
),
|
||||||
ty::ImplContainer => {
|
ty::ImplContainer => {
|
||||||
if segments.len() == 1 {
|
if segments.len() == 1 {
|
||||||
// `<T>::assoc` will end up here, and so
|
// `<T>::assoc` will end up here, and so
|
||||||
@ -1478,12 +1497,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
Ok(normalized_ty) => normalized_ty,
|
Ok(normalized_ty) => normalized_ty,
|
||||||
Err(errors) => {
|
Err(errors) => {
|
||||||
let guar = self.err_ctxt().report_fulfillment_errors(errors);
|
let guar = self.err_ctxt().report_fulfillment_errors(errors);
|
||||||
return Ty::new_error(self.tcx,guar);
|
return Ty::new_error(self.tcx, guar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves `ty` by a single level if `ty` is a type variable.
|
/// Resolves `ty` by a single level if `ty` is a type variable.
|
||||||
|
@ -129,21 +129,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for param in
|
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||||
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
if self.blame_specific_arg_if_possible(
|
if self.blame_specific_arg_if_possible(
|
||||||
error,
|
error,
|
||||||
def_id,
|
def_id,
|
||||||
param,
|
param,
|
||||||
*call_hir_id,
|
*call_hir_id,
|
||||||
callee.span,
|
callee.span,
|
||||||
None,
|
None,
|
||||||
args,
|
args,
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,8 +344,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&& let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind
|
&& let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind
|
||||||
&& let generics = self.0.tcx.generics_of(self.1)
|
&& let generics = self.0.tcx.generics_of(self.1)
|
||||||
&& let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
|
&& let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
|
||||||
&& let Some(subst) = ty::GenericArgs::identity_for_item(self.0.tcx, self.1)
|
&& let Some(subst) =
|
||||||
.get(index as usize)
|
ty::GenericArgs::identity_for_item(self.0.tcx, self.1).get(index as usize)
|
||||||
{
|
{
|
||||||
ControlFlow::Break(*subst)
|
ControlFlow::Break(*subst)
|
||||||
} else {
|
} else {
|
||||||
@ -364,11 +362,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let traits::FulfillmentErrorCode::CodeSelectionError(
|
if let traits::FulfillmentErrorCode::CodeSelectionError(
|
||||||
traits::SelectionError::OutputTypeParameterMismatch(box traits::SelectionOutputTypeParameterMismatch{
|
traits::SelectionError::OutputTypeParameterMismatch(
|
||||||
expected_trait_ref, ..
|
box traits::SelectionOutputTypeParameterMismatch { expected_trait_ref, .. },
|
||||||
}),
|
),
|
||||||
) = error.code
|
) = error.code
|
||||||
&& let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected_trait_ref.skip_binder().self_ty().kind()
|
&& let ty::Closure(def_id, _) | ty::Generator(def_id, ..) =
|
||||||
|
expected_trait_ref.skip_binder().self_ty().kind()
|
||||||
&& span.overlaps(self.tcx.def_span(*def_id))
|
&& span.overlaps(self.tcx.def_span(*def_id))
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
@ -446,10 +445,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.collect();
|
.collect();
|
||||||
// If there's one field that references the given generic, great!
|
// If there's one field that references the given generic, great!
|
||||||
if let [(idx, _)] = args_referencing_param.as_slice()
|
if let [(idx, _)] = args_referencing_param.as_slice()
|
||||||
&& let Some(arg) = receiver
|
&& let Some(arg) = receiver.map_or(args.get(*idx), |rcvr| {
|
||||||
.map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
|
if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }
|
||||||
|
})
|
||||||
error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
|
{
|
||||||
|
error.obligation.cause.span = arg
|
||||||
|
.span
|
||||||
|
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
|
||||||
|
.unwrap_or(arg.span);
|
||||||
|
|
||||||
if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
|
if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
|
||||||
// This is more specific than pointing at the entire argument.
|
// This is more specific than pointing at the entire argument.
|
||||||
@ -934,16 +937,16 @@ fn find_param_in_ty<'tcx>(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||||
&& let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
|
&& let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
|
||||||
{
|
{
|
||||||
// This logic may seem a bit strange, but typically when
|
// This logic may seem a bit strange, but typically when
|
||||||
// we have a projection type in a function signature, the
|
// we have a projection type in a function signature, the
|
||||||
// argument that's being passed into that signature is
|
// argument that's being passed into that signature is
|
||||||
// not actually constraining that projection's args in
|
// not actually constraining that projection's args in
|
||||||
// a meaningful way. So we skip it, and see improvements
|
// a meaningful way. So we skip it, and see improvements
|
||||||
// in some UI tests.
|
// in some UI tests.
|
||||||
walk.skip_current_subtree();
|
walk.skip_current_subtree();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -652,7 +652,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
|
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
|
||||||
{
|
{
|
||||||
// Wrap up the N provided arguments starting at this position in a tuple.
|
// Wrap up the N provided arguments starting at this position in a tuple.
|
||||||
let provided_as_tuple = Ty::new_tup_from_iter(tcx,
|
let provided_as_tuple = Ty::new_tup_from_iter(
|
||||||
|
tcx,
|
||||||
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
|
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -884,8 +885,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&& self.tcx.def_kind(fn_def_id).is_fn_like()
|
&& self.tcx.def_kind(fn_def_id).is_fn_like()
|
||||||
&& let self_implicit =
|
&& let self_implicit =
|
||||||
matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize
|
matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize
|
||||||
&& let Some(arg) = self.tcx.fn_arg_names(fn_def_id)
|
&& let Some(arg) =
|
||||||
.get(expected_idx.as_usize() + self_implicit)
|
self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit)
|
||||||
&& arg.name != kw::SelfLower
|
&& arg.name != kw::SelfLower
|
||||||
{
|
{
|
||||||
format!("/* {} */", arg.name)
|
format!("/* {} */", arg.name)
|
||||||
@ -946,9 +947,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&& error_span.can_be_used_for_suggestions()
|
&& error_span.can_be_used_for_suggestions()
|
||||||
{
|
{
|
||||||
if arg_idx.index() > 0
|
if arg_idx.index() > 0
|
||||||
&& let Some((_, prev)) = provided_arg_tys
|
&& let Some((_, prev)) =
|
||||||
.get(ProvidedIdx::from_usize(arg_idx.index() - 1)
|
provided_arg_tys.get(ProvidedIdx::from_usize(arg_idx.index() - 1))
|
||||||
) {
|
{
|
||||||
// Include previous comma
|
// Include previous comma
|
||||||
span = prev.shrink_to_hi().to(span);
|
span = prev.shrink_to_hi().to(span);
|
||||||
}
|
}
|
||||||
@ -1291,7 +1292,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
err: &mut rustc_errors::DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
err: &mut rustc_errors::DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||||
) {
|
) {
|
||||||
if let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Mut, .. }) = expected_ty.kind()
|
if let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Mut, .. }) = expected_ty.kind()
|
||||||
&& let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, .. }) = provided_ty.kind()
|
&& let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, .. }) =
|
||||||
|
provided_ty.kind()
|
||||||
&& let hir::ExprKind::Call(callee, _) = arg.kind
|
&& let hir::ExprKind::Call(callee, _) = arg.kind
|
||||||
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind
|
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind
|
||||||
&& let Res::Def(_, def_id) = path.res
|
&& let Res::Def(_, def_id) = path.res
|
||||||
@ -1299,9 +1301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
// The user provided `ptr::null()`, but the function expects
|
// The user provided `ptr::null()`, but the function expects
|
||||||
// `ptr::null_mut()`.
|
// `ptr::null_mut()`.
|
||||||
err.subdiagnostic(SuggestPtrNullMut {
|
err.subdiagnostic(SuggestPtrNullMut { span: arg.span });
|
||||||
span: arg.span
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1928,8 +1928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let callee_ty = callee_ty.peel_refs();
|
let callee_ty = callee_ty.peel_refs();
|
||||||
match *callee_ty.kind() {
|
match *callee_ty.kind() {
|
||||||
ty::Param(param) => {
|
ty::Param(param) => {
|
||||||
let param =
|
let param = self.tcx.generics_of(self.body_id).type_param(¶m, self.tcx);
|
||||||
self.tcx.generics_of(self.body_id).type_param(¶m, self.tcx);
|
|
||||||
if param.kind.is_synthetic() {
|
if param.kind.is_synthetic() {
|
||||||
// if it's `impl Fn() -> ..` then just fall down to the def-id based logic
|
// if it's `impl Fn() -> ..` then just fall down to the def-id based logic
|
||||||
def_id = param.def_id;
|
def_id = param.def_id;
|
||||||
@ -1943,8 +1942,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// FIXME(compiler-errors): This could be problematic if something has two
|
// FIXME(compiler-errors): This could be problematic if something has two
|
||||||
// fn-like predicates with different args, but callable types really never
|
// fn-like predicates with different args, but callable types really never
|
||||||
// do that, so it's OK.
|
// do that, so it's OK.
|
||||||
for (predicate, span) in instantiated
|
for (predicate, span) in instantiated {
|
||||||
{
|
|
||||||
if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder()
|
if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder()
|
||||||
&& pred.self_ty().peel_refs() == callee_ty
|
&& pred.self_ty().peel_refs() == callee_ty
|
||||||
&& self.tcx.is_fn_trait(pred.def_id())
|
&& self.tcx.is_fn_trait(pred.def_id())
|
||||||
@ -1963,7 +1961,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
_ => {
|
_ => {
|
||||||
// Look for a user-provided impl of a `Fn` trait, and point to it.
|
// Look for a user-provided impl of a `Fn` trait, and point to it.
|
||||||
let new_def_id = self.probe(|_| {
|
let new_def_id = self.probe(|_| {
|
||||||
let trait_ref = ty::TraitRef::new(self.tcx,
|
let trait_ref = ty::TraitRef::new(
|
||||||
|
self.tcx,
|
||||||
call_kind.to_def_id(self.tcx),
|
call_kind.to_def_id(self.tcx),
|
||||||
[
|
[
|
||||||
callee_ty,
|
callee_ty,
|
||||||
@ -1995,7 +1994,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() {
|
if let Some(def_span) = self.tcx.def_ident_span(def_id)
|
||||||
|
&& !def_span.is_dummy()
|
||||||
|
{
|
||||||
let mut spans: MultiSpan = def_span.into();
|
let mut spans: MultiSpan = def_span.into();
|
||||||
|
|
||||||
let params = self
|
let params = self
|
||||||
@ -2025,7 +2026,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// Try to find earlier invocations of this closure to find if the type mismatch
|
// Try to find earlier invocations of this closure to find if the type mismatch
|
||||||
// is because of inference. If we find one, point at them.
|
// is because of inference. If we find one, point at them.
|
||||||
let mut call_finder = FindClosureArg { tcx: self.tcx, calls: vec![] };
|
let mut call_finder = FindClosureArg { tcx: self.tcx, calls: vec![] };
|
||||||
let node = self.tcx
|
let node = self
|
||||||
|
.tcx
|
||||||
.opt_local_def_id_to_hir_id(self.tcx.hir().get_parent_item(call_expr.hir_id))
|
.opt_local_def_id_to_hir_id(self.tcx.hir().get_parent_item(call_expr.hir_id))
|
||||||
.and_then(|hir_id| self.tcx.hir().find(hir_id));
|
.and_then(|hir_id| self.tcx.hir().find(hir_id));
|
||||||
match node {
|
match node {
|
||||||
|
@ -254,22 +254,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
expr: &hir::Expr<'tcx>,
|
expr: &hir::Expr<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) = expr.kind &&
|
if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) =
|
||||||
let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr) &&
|
expr.kind
|
||||||
self.can_coerce(recv_ty, expected) {
|
&& let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr)
|
||||||
let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) {
|
&& self.can_coerce(recv_ty, expected)
|
||||||
expr.span.with_lo(recv_span.hi())
|
{
|
||||||
} else {
|
let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) {
|
||||||
expr.span.with_lo(method.span.lo() - rustc_span::BytePos(1))
|
expr.span.with_lo(recv_span.hi())
|
||||||
};
|
} else {
|
||||||
err.span_suggestion_verbose(
|
expr.span.with_lo(method.span.lo() - rustc_span::BytePos(1))
|
||||||
span,
|
};
|
||||||
"try removing the method call",
|
err.span_suggestion_verbose(
|
||||||
"",
|
span,
|
||||||
Applicability::MachineApplicable,
|
"try removing the method call",
|
||||||
);
|
"",
|
||||||
return true;
|
Applicability::MachineApplicable,
|
||||||
}
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,10 +349,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let name = self.tcx.item_name(def_id);
|
let name = self.tcx.item_name(def_id);
|
||||||
let kind = self.tcx.def_kind(def_id);
|
let kind = self.tcx.def_kind(def_id);
|
||||||
if let DefKind::Ctor(of, CtorKind::Fn) = kind {
|
if let DefKind::Ctor(of, CtorKind::Fn) = kind {
|
||||||
err.span_label(sp, format!("`{name}` defines {} constructor here, which should be called", match of {
|
err.span_label(
|
||||||
CtorOf::Struct => "a struct",
|
sp,
|
||||||
CtorOf::Variant => "an enum variant",
|
format!(
|
||||||
}));
|
"`{name}` defines {} constructor here, which should be called",
|
||||||
|
match of {
|
||||||
|
CtorOf::Struct => "a struct",
|
||||||
|
CtorOf::Variant => "an enum variant",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
let descr = self.tcx.def_kind_descr(kind, def_id);
|
let descr = self.tcx.def_kind_descr(kind, def_id);
|
||||||
err.span_label(sp, format!("{descr} `{name}` defined here"));
|
err.span_label(sp, format!("{descr} `{name}` defined here"));
|
||||||
@ -370,25 +378,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if let Some(method_ident) = receiver_method_ident
|
if let Some(method_ident) = receiver_method_ident
|
||||||
&& method_ident.name == conversion_method.name
|
&& method_ident.name == conversion_method.name
|
||||||
{
|
{
|
||||||
return None // do not suggest code that is already there (#53348)
|
return None; // do not suggest code that is already there (#53348)
|
||||||
}
|
}
|
||||||
|
|
||||||
let method_call_list = [sym::to_vec, sym::to_string];
|
let method_call_list = [sym::to_vec, sym::to_string];
|
||||||
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
|
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
|
||||||
&& receiver_method.ident.name == sym::clone
|
&& receiver_method.ident.name == sym::clone
|
||||||
&& method_call_list.contains(&conversion_method.name)
|
&& method_call_list.contains(&conversion_method.name)
|
||||||
// If receiver is `.clone()` and found type has one of those methods,
|
// If receiver is `.clone()` and found type has one of those methods,
|
||||||
// we guess that the user wants to convert from a slice type (`&[]` or `&str`)
|
// we guess that the user wants to convert from a slice type (`&[]` or `&str`)
|
||||||
// to an owned type (`Vec` or `String`). These conversions clone internally,
|
// to an owned type (`Vec` or `String`). These conversions clone internally,
|
||||||
// so we remove the user's `clone` call.
|
// so we remove the user's `clone` call.
|
||||||
{
|
|
||||||
vec![(
|
|
||||||
receiver_method.ident.span,
|
|
||||||
conversion_method.name.to_string()
|
|
||||||
)]
|
|
||||||
} else if expr.precedence().order()
|
|
||||||
< ExprPrecedence::MethodCall.order()
|
|
||||||
{
|
{
|
||||||
|
vec![(receiver_method.ident.span, conversion_method.name.to_string())]
|
||||||
|
} else if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
|
||||||
vec![
|
vec![
|
||||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||||
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
|
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
|
||||||
@ -431,7 +434,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
|
// Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
|
||||||
// `as_ref` and `as_deref` compatibility.
|
// `as_ref` and `as_deref` compatibility.
|
||||||
let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| {
|
let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| {
|
||||||
self.can_eq(self.param_env, Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_erased, found), expected)
|
self.can_eq(
|
||||||
|
self.param_env,
|
||||||
|
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, found),
|
||||||
|
expected,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
// FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
|
// FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
|
||||||
// but those checks need to be a bit more delicate and the benefit is diminishing.
|
// but those checks need to be a bit more delicate and the benefit is diminishing.
|
||||||
@ -770,41 +777,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
|
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
|
||||||
if let Some(found) = found.make_suggestable(self.tcx, false) {
|
if let Some(found) = found.make_suggestable(self.tcx, false) {
|
||||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() });
|
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
|
||||||
|
span,
|
||||||
|
found: found.to_string(),
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
} else if let ty::Closure(_, args) = found.kind()
|
} else if let ty::Closure(_, args) = found.kind()
|
||||||
// FIXME(compiler-errors): Get better at printing binders...
|
// FIXME(compiler-errors): Get better at printing binders...
|
||||||
&& let closure = args.as_closure()
|
&& let closure = args.as_closure()
|
||||||
&& closure.sig().is_suggestable(self.tcx, false)
|
&& closure.sig().is_suggestable(self.tcx, false)
|
||||||
{
|
{
|
||||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() });
|
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
|
||||||
|
span,
|
||||||
|
found: closure.print_as_impl_trait().to_string(),
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// FIXME: if `found` could be `impl Iterator` we should suggest that.
|
// FIXME: if `found` could be `impl Iterator` we should suggest that.
|
||||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
|
err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::FnRetTy::Return(hir_ty) => {
|
hir::FnRetTy::Return(hir_ty) => {
|
||||||
if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
|
if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
|
||||||
&& let hir::Node::Item(hir::Item {
|
&& let hir::Node::Item(hir::Item {
|
||||||
kind: hir::ItemKind::OpaqueTy(op_ty),
|
kind: hir::ItemKind::OpaqueTy(op_ty), ..
|
||||||
..
|
|
||||||
}) = self.tcx.hir().get(item_id.hir_id())
|
}) = self.tcx.hir().get(item_id.hir_id())
|
||||||
&& let [hir::GenericBound::LangItemTrait(
|
&& let [
|
||||||
hir::LangItem::Future, _, _, generic_args)] = op_ty.bounds
|
hir::GenericBound::LangItemTrait(hir::LangItem::Future, _, _, generic_args),
|
||||||
|
] = op_ty.bounds
|
||||||
&& let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args
|
&& let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args
|
||||||
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } = ty_binding.kind
|
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } =
|
||||||
|
ty_binding.kind
|
||||||
{
|
{
|
||||||
// Check if async function's return type was omitted.
|
// Check if async function's return type was omitted.
|
||||||
// Don't emit suggestions if the found type is `impl Future<...>`.
|
// Don't emit suggestions if the found type is `impl Future<...>`.
|
||||||
debug!(?found);
|
debug!(?found);
|
||||||
if found.is_suggestable(self.tcx, false) {
|
if found.is_suggestable(self.tcx, false) {
|
||||||
if term.span.is_empty() {
|
if term.span.is_empty() {
|
||||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span: term.span, found: found.to_string() });
|
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
|
||||||
|
span: term.span,
|
||||||
|
found: found.to_string(),
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: term.span, expected });
|
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
|
||||||
|
span: term.span,
|
||||||
|
expected,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -819,7 +839,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let ty = self.normalize(hir_ty.span, ty);
|
let ty = self.normalize(hir_ty.span, ty);
|
||||||
let ty = self.tcx.erase_late_bound_regions(ty);
|
let ty = self.tcx.erase_late_bound_regions(ty);
|
||||||
if self.can_coerce(expected, ty) {
|
if self.can_coerce(expected, ty) {
|
||||||
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected });
|
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
|
||||||
|
span: hir_ty.span,
|
||||||
|
expected,
|
||||||
|
});
|
||||||
self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
|
self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1077,13 +1100,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.type_implements_trait(
|
.type_implements_trait(
|
||||||
clone_trait_def,
|
clone_trait_def,
|
||||||
[self.tcx.erase_regions(expected_ty)],
|
[self.tcx.erase_regions(expected_ty)],
|
||||||
self.param_env
|
self.param_env,
|
||||||
)
|
)
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
{
|
{
|
||||||
let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
|
let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
|
||||||
Some(ident) => format!(": {ident}.clone()"),
|
Some(ident) => format!(": {ident}.clone()"),
|
||||||
None => ".clone()".to_string()
|
None => ".clone()".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
diag.span_suggestion_verbose(
|
diag.span_suggestion_verbose(
|
||||||
@ -1093,7 +1116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1121,31 +1144,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let expr_inner_ty = args.type_at(0);
|
let expr_inner_ty = args.type_at(0);
|
||||||
let expected_inner_ty = expected_args.type_at(0);
|
let expected_inner_ty = expected_args.type_at(0);
|
||||||
if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind()
|
if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind()
|
||||||
&& self.can_eq(self.param_env, ty, expected_inner_ty)
|
&& self.can_eq(self.param_env, ty, expected_inner_ty)
|
||||||
|
{
|
||||||
|
let def_path = self.tcx.def_path_str(adt_def.did());
|
||||||
|
let span = expr.span.shrink_to_hi();
|
||||||
|
let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) {
|
||||||
|
errors::OptionResultRefMismatch::Copied { span, def_path }
|
||||||
|
} else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
|
||||||
|
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
|
||||||
|
self,
|
||||||
|
self.param_env,
|
||||||
|
ty,
|
||||||
|
clone_did,
|
||||||
|
)
|
||||||
{
|
{
|
||||||
let def_path = self.tcx.def_path_str(adt_def.did());
|
errors::OptionResultRefMismatch::Cloned { span, def_path }
|
||||||
let span = expr.span.shrink_to_hi();
|
} else {
|
||||||
let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) {
|
return false;
|
||||||
errors::OptionResultRefMismatch::Copied {
|
};
|
||||||
span, def_path
|
diag.subdiagnostic(subdiag);
|
||||||
}
|
return true;
|
||||||
} else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
|
}
|
||||||
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
|
|
||||||
self,
|
|
||||||
self.param_env,
|
|
||||||
ty,
|
|
||||||
clone_did,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
errors::OptionResultRefMismatch::Cloned {
|
|
||||||
span, def_path
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
diag.subdiagnostic(subdiag);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
@ -1181,14 +1200,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.tcx,
|
self.tcx,
|
||||||
self.misc(expr.span),
|
self.misc(expr.span),
|
||||||
self.param_env,
|
self.param_env,
|
||||||
ty::TraitRef::new(self.tcx,
|
ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
|
||||||
into_def_id,
|
|
||||||
[expr_ty, expected_ty]
|
|
||||||
),
|
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
let mut span = expr.span;
|
let mut span = expr.span;
|
||||||
while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite()
|
while expr.span.eq_ctxt(span)
|
||||||
|
&& let Some(parent_callsite) = span.parent_callsite()
|
||||||
{
|
{
|
||||||
span = parent_callsite;
|
span = parent_callsite;
|
||||||
}
|
}
|
||||||
@ -1196,7 +1213,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
|
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
|
||||||
vec![(span.shrink_to_hi(), ".into()".to_owned())]
|
vec![(span.shrink_to_hi(), ".into()".to_owned())]
|
||||||
} else {
|
} else {
|
||||||
vec![(span.shrink_to_lo(), "(".to_owned()), (span.shrink_to_hi(), ").into()".to_owned())]
|
vec![
|
||||||
|
(span.shrink_to_lo(), "(".to_owned()),
|
||||||
|
(span.shrink_to_hi(), ").into()".to_owned()),
|
||||||
|
]
|
||||||
};
|
};
|
||||||
diag.multipart_suggestion(
|
diag.multipart_suggestion(
|
||||||
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
|
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
|
||||||
@ -1238,9 +1258,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// since the user probably just misunderstood how `let else`
|
// since the user probably just misunderstood how `let else`
|
||||||
// and `&&` work together.
|
// and `&&` work together.
|
||||||
if let Some((_, hir::Node::Local(local))) = cond_parent
|
if let Some((_, hir::Node::Local(local))) = cond_parent
|
||||||
&& let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
|
&& let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) =
|
||||||
|
&local.pat.kind
|
||||||
&& let hir::QPath::Resolved(None, path) = qpath
|
&& let hir::QPath::Resolved(None, path) = qpath
|
||||||
&& let Some(did) = path.res.opt_def_id()
|
&& let Some(did) = path
|
||||||
|
.res
|
||||||
|
.opt_def_id()
|
||||||
.and_then(|did| self.tcx.opt_parent(did))
|
.and_then(|did| self.tcx.opt_parent(did))
|
||||||
.and_then(|did| self.tcx.opt_parent(did))
|
.and_then(|did| self.tcx.opt_parent(did))
|
||||||
&& self.tcx.is_diagnostic_item(sym::Option, did)
|
&& self.tcx.is_diagnostic_item(sym::Option, did)
|
||||||
@ -1607,7 +1630,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) =
|
let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) =
|
||||||
self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id)) else {
|
self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id))
|
||||||
|
else {
|
||||||
return expr;
|
return expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1634,12 +1658,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// to worry if it's a call to a typed function or closure as this would ne handled
|
// to worry if it's a call to a typed function or closure as this would ne handled
|
||||||
// previously.
|
// previously.
|
||||||
hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => {
|
hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => {
|
||||||
if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) = call_expr_kind
|
if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) =
|
||||||
&& let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } = call_expr_path
|
call_expr_kind
|
||||||
&& let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.hir().find(*binding)
|
&& let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } =
|
||||||
|
call_expr_path
|
||||||
|
&& let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) =
|
||||||
|
self.tcx.hir().find(*binding)
|
||||||
&& let Some(closure) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id))
|
&& let Some(closure) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id))
|
||||||
&& let hir::Node::Local(hir::Local { init: Some(init), .. }) = closure
|
&& let hir::Node::Local(hir::Local { init: Some(init), .. }) = closure
|
||||||
&& let Expr { kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), ..} = init
|
&& let Expr {
|
||||||
|
kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }),
|
||||||
|
..
|
||||||
|
} = init
|
||||||
{
|
{
|
||||||
let hir::Body { value: body_expr, .. } = self.tcx.hir().body(*body_id);
|
let hir::Body { value: body_expr, .. } = self.tcx.hir().body(*body_id);
|
||||||
self.note_type_is_not_clone_inner_expr(body_expr)
|
self.note_type_is_not_clone_inner_expr(body_expr)
|
||||||
|
@ -129,25 +129,29 @@ impl<'tcx> Inherited<'tcx> {
|
|||||||
let infer_var_info = &mut self.infer_var_info.borrow_mut();
|
let infer_var_info = &mut self.infer_var_info.borrow_mut();
|
||||||
|
|
||||||
// (*) binder skipped
|
// (*) binder skipped
|
||||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) = obligation.predicate.kind().skip_binder()
|
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) =
|
||||||
&& let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
|
obligation.predicate.kind().skip_binder()
|
||||||
|
&& let Some(ty) =
|
||||||
|
self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
|
||||||
&& self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id)
|
&& self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id)
|
||||||
{
|
{
|
||||||
let new_self_ty = self.tcx.types.unit;
|
let new_self_ty = self.tcx.types.unit;
|
||||||
|
|
||||||
// Then construct a new obligation with Self = () added
|
// Then construct a new obligation with Self = () added
|
||||||
// to the ParamEnv, and see if it holds.
|
// to the ParamEnv, and see if it holds.
|
||||||
let o = obligation.with(self.tcx,
|
let o = obligation.with(
|
||||||
obligation
|
self.tcx,
|
||||||
.predicate
|
obligation.predicate.kind().rebind(
|
||||||
.kind()
|
// (*) binder moved here
|
||||||
.rebind(
|
ty::PredicateKind::Clause(ty::ClauseKind::Trait(
|
||||||
// (*) binder moved here
|
tpred.with_self_ty(self.tcx, new_self_ty),
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred.with_self_ty(self.tcx, new_self_ty)))
|
)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
// Don't report overflow errors. Otherwise equivalent to may_hold.
|
// Don't report overflow errors. Otherwise equivalent to may_hold.
|
||||||
if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o)) && result.may_apply() {
|
if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o))
|
||||||
|
&& result.may_apply()
|
||||||
|
{
|
||||||
infer_var_info.entry(ty).or_default().self_in_trait = true;
|
infer_var_info.entry(ty).or_default().self_in_trait = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// Special-case transmuting from `typeof(function)` and
|
// Special-case transmuting from `typeof(function)` and
|
||||||
// `Option<typeof(function)>` to present a clearer error.
|
// `Option<typeof(function)>` to present a clearer error.
|
||||||
let from = unpack_option_like(tcx, from);
|
let from = unpack_option_like(tcx, from);
|
||||||
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) {
|
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to)
|
||||||
|
&& size_to == Pointer(dl.instruction_address_space).size(&tcx)
|
||||||
|
{
|
||||||
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
|
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
|
||||||
.note(format!("source type: {from}"))
|
.note(format!("source type: {from}"))
|
||||||
.note(format!("target type: {to}"))
|
.note(format!("target type: {to}"))
|
||||||
|
@ -667,8 +667,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
// will still match the original object type, but it won't pollute our
|
// will still match the original object type, but it won't pollute our
|
||||||
// type variables in any form, so just do that!
|
// type variables in any form, so just do that!
|
||||||
let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) =
|
let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) =
|
||||||
self.fcx
|
self.fcx.instantiate_canonical_with_fresh_inference_vars(self.span, self_ty);
|
||||||
.instantiate_canonical_with_fresh_inference_vars(self.span, self_ty);
|
|
||||||
|
|
||||||
self.assemble_inherent_candidates_from_object(generalized_self_ty);
|
self.assemble_inherent_candidates_from_object(generalized_self_ty);
|
||||||
self.assemble_inherent_impl_candidates_for_type(p.def_id());
|
self.assemble_inherent_impl_candidates_for_type(p.def_id());
|
||||||
@ -1690,15 +1689,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty);
|
||||||
"comparing return_ty {:?} with xform ret ty {:?}",
|
|
||||||
return_ty, xform_ret_ty
|
|
||||||
);
|
|
||||||
if let ProbeResult::Match = result
|
if let ProbeResult::Match = result
|
||||||
&& self
|
&& self
|
||||||
.at(&ObligationCause::dummy(), self.param_env)
|
.at(&ObligationCause::dummy(), self.param_env)
|
||||||
.sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty)
|
.sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
result = ProbeResult::BadReturnType;
|
result = ProbeResult::BadReturnType;
|
||||||
}
|
}
|
||||||
@ -1959,15 +1955,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
if let Some(nested) = v.meta_item_list() {
|
if let Some(nested) = v.meta_item_list() {
|
||||||
// #[doc(alias("foo", "bar"))]
|
// #[doc(alias("foo", "bar"))]
|
||||||
for n in nested {
|
for n in nested {
|
||||||
if let Some(lit) = n.lit() && name.as_str() == lit.symbol.as_str() {
|
if let Some(lit) = n.lit()
|
||||||
|
&& name.as_str() == lit.symbol.as_str()
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Some(meta) = v.meta_item()
|
} else if let Some(meta) = v.meta_item()
|
||||||
&& let Some(lit) = meta.name_value_literal()
|
&& let Some(lit) = meta.name_value_literal()
|
||||||
&& name.as_str() == lit.symbol.as_str() {
|
&& name.as_str() == lit.symbol.as_str()
|
||||||
// #[doc(alias = "foo")]
|
{
|
||||||
return true;
|
// #[doc(alias = "foo")]
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,8 +305,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let mode = no_match_data.mode;
|
let mode = no_match_data.mode;
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
|
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
|
||||||
let ((mut ty_str, ty_file), short_ty_str) = if trait_missing_method
|
let ((mut ty_str, ty_file), short_ty_str) =
|
||||||
&& let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
|
if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
|
||||||
((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string()))
|
((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string()))
|
||||||
} else {
|
} else {
|
||||||
(tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string()))
|
(tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string()))
|
||||||
@ -377,9 +377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
tcx.is_diagnostic_item(sym::write_macro, def_id)
|
tcx.is_diagnostic_item(sym::write_macro, def_id)
|
||||||
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
|
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
|
||||||
}) && item_name.name == Symbol::intern("write_fmt");
|
}) && item_name.name == Symbol::intern("write_fmt");
|
||||||
let mut err = if is_write
|
let mut err = if is_write && let Some(args) = args {
|
||||||
&& let Some(args) = args
|
|
||||||
{
|
|
||||||
self.suggest_missing_writer(rcvr_ty, args)
|
self.suggest_missing_writer(rcvr_ty, args)
|
||||||
} else {
|
} else {
|
||||||
tcx.sess.create_err(NoAssociatedItem {
|
tcx.sess.create_err(NoAssociatedItem {
|
||||||
@ -421,9 +419,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
|
if let Mode::MethodCall = mode
|
||||||
|
&& let SelfSource::MethodCall(cal) = source
|
||||||
|
{
|
||||||
self.suggest_await_before_method(
|
self.suggest_await_before_method(
|
||||||
&mut err, item_name, rcvr_ty, cal, span, expected.only_has_type(self),
|
&mut err,
|
||||||
|
item_name,
|
||||||
|
rcvr_ty,
|
||||||
|
cal,
|
||||||
|
span,
|
||||||
|
expected.only_has_type(self),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let Some(span) =
|
if let Some(span) =
|
||||||
@ -863,7 +868,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.filter_map(|(pred, parent_pred, _cause)| {
|
.filter_map(|(pred, parent_pred, _cause)| {
|
||||||
let mut suggested = false;
|
let mut suggested = false;
|
||||||
format_pred(*pred).map(|(p, self_ty)| {
|
format_pred(*pred).map(|(p, self_ty)| {
|
||||||
if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
|
if let Some(parent) = parent_pred
|
||||||
|
&& suggested_bounds.contains(parent)
|
||||||
|
{
|
||||||
// We don't suggest `PartialEq` when we already suggest `Eq`.
|
// We don't suggest `PartialEq` when we already suggest `Eq`.
|
||||||
} else if !suggested_bounds.contains(pred) {
|
} else if !suggested_bounds.contains(pred) {
|
||||||
if collect_type_param_suggestions(self_ty, *pred, &p) {
|
if collect_type_param_suggestions(self_ty, *pred, &p) {
|
||||||
@ -967,7 +974,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
unsatisfied_bounds = true;
|
unsatisfied_bounds = true;
|
||||||
}
|
}
|
||||||
} else if let ty::Adt(def, targs) = rcvr_ty.kind() && let Some(args) = args {
|
} else if let ty::Adt(def, targs) = rcvr_ty.kind()
|
||||||
|
&& let Some(args) = args
|
||||||
|
{
|
||||||
// This is useful for methods on arbitrary self types that might have a simple
|
// This is useful for methods on arbitrary self types that might have a simple
|
||||||
// mutability difference, like calling a method on `Pin<&mut Self>` that is on
|
// mutability difference, like calling a method on `Pin<&mut Self>` that is on
|
||||||
// `Pin<&Self>`.
|
// `Pin<&Self>`.
|
||||||
@ -975,16 +984,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let mut item_segment = hir::PathSegment::invalid();
|
let mut item_segment = hir::PathSegment::invalid();
|
||||||
item_segment.ident = item_name;
|
item_segment.ident = item_name;
|
||||||
for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] {
|
for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] {
|
||||||
let new_args = tcx.mk_args_from_iter(
|
let new_args =
|
||||||
targs
|
tcx.mk_args_from_iter(targs.iter().map(|arg| match arg.as_type() {
|
||||||
.iter()
|
Some(ty) => ty::GenericArg::from(t(
|
||||||
.map(|arg| match arg.as_type() {
|
tcx,
|
||||||
Some(ty) => ty::GenericArg::from(
|
tcx.lifetimes.re_erased,
|
||||||
t(tcx, tcx.lifetimes.re_erased, ty.peel_refs()),
|
ty.peel_refs(),
|
||||||
),
|
)),
|
||||||
_ => arg,
|
_ => arg,
|
||||||
})
|
}));
|
||||||
);
|
|
||||||
let rcvr_ty = Ty::new_adt(tcx, *def, new_args);
|
let rcvr_ty = Ty::new_adt(tcx, *def, new_args);
|
||||||
if let Ok(method) = self.lookup_method_for_diagnostic(
|
if let Ok(method) = self.lookup_method_for_diagnostic(
|
||||||
rcvr_ty,
|
rcvr_ty,
|
||||||
@ -1088,7 +1096,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
for inherent_method in
|
for inherent_method in
|
||||||
self.tcx.associated_items(inherent_impl_did).in_definition_order()
|
self.tcx.associated_items(inherent_impl_did).in_definition_order()
|
||||||
{
|
{
|
||||||
if let Some(attr) = self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables)
|
if let Some(attr) = self
|
||||||
|
.tcx
|
||||||
|
.get_attr(inherent_method.def_id, sym::rustc_confusables)
|
||||||
&& let Some(candidates) = parse_confusables(attr)
|
&& let Some(candidates) = parse_confusables(attr)
|
||||||
&& candidates.contains(&item_name.name)
|
&& candidates.contains(&item_name.name)
|
||||||
{
|
{
|
||||||
@ -1307,7 +1317,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
err.note(note_str);
|
err.note(note_str);
|
||||||
}
|
}
|
||||||
if let Some(sugg_span) = sugg_span
|
if let Some(sugg_span) = sugg_span
|
||||||
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
|
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did)
|
||||||
|
{
|
||||||
let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
|
let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
|
||||||
|
|
||||||
let ty = match item.kind {
|
let ty = match item.kind {
|
||||||
@ -1453,10 +1464,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&& assoc.kind == ty::AssocKind::Fn
|
&& assoc.kind == ty::AssocKind::Fn
|
||||||
{
|
{
|
||||||
let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity();
|
let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity();
|
||||||
sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() {
|
sig.inputs().skip_binder().get(0).and_then(|first| {
|
||||||
None
|
if first.peel_refs() == rcvr_ty.peel_refs() {
|
||||||
} else {
|
None
|
||||||
Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
|
} else {
|
||||||
|
Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -1729,8 +1742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let span = tcx.hir().span(hir_id);
|
let span = tcx.hir().span(hir_id);
|
||||||
let filename = tcx.sess.source_map().span_to_filename(span);
|
let filename = tcx.sess.source_map().span_to_filename(span);
|
||||||
|
|
||||||
let parent_node =
|
let parent_node = self.tcx.hir().get_parent(hir_id);
|
||||||
self.tcx.hir().get_parent(hir_id);
|
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"you must specify a type for this binding, like `{concrete_type}`",
|
"you must specify a type for this binding, like `{concrete_type}`",
|
||||||
);
|
);
|
||||||
@ -1744,7 +1756,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
) => {
|
) => {
|
||||||
let type_span = ty.map(|ty| ty.span.with_lo(span.hi())).unwrap_or(span.shrink_to_hi());
|
let type_span = ty
|
||||||
|
.map(|ty| ty.span.with_lo(span.hi()))
|
||||||
|
.unwrap_or(span.shrink_to_hi());
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
// account for `let x: _ = 42;`
|
// account for `let x: _ = 42;`
|
||||||
// ^^^
|
// ^^^
|
||||||
@ -1843,9 +1857,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
return_type: Option<Ty<'tcx>>,
|
return_type: Option<Ty<'tcx>>,
|
||||||
) {
|
) {
|
||||||
if let SelfSource::MethodCall(expr) = source
|
if let SelfSource::MethodCall(expr) = source
|
||||||
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
|
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
|
||||||
&& let Some((fields, args)) =
|
&& let Some((fields, args)) =
|
||||||
self.get_field_candidates_considering_privacy(span, actual, mod_id)
|
self.get_field_candidates_considering_privacy(span, actual, mod_id)
|
||||||
{
|
{
|
||||||
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
|
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
|
||||||
|
|
||||||
@ -2324,7 +2338,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// <&[_]>::len or <&[u32]>::len doesn't need an extra "<>" between
|
// <&[_]>::len or <&[u32]>::len doesn't need an extra "<>" between
|
||||||
// but for Adt type like Vec::function()
|
// but for Adt type like Vec::function()
|
||||||
// we would suggest <[_]>::function();
|
// we would suggest <[_]>::function();
|
||||||
_ if self.tcx.sess.source_map().span_wrapped_by_angle_or_parentheses(ty.span) => format!("{deref_ty}"),
|
_ if self
|
||||||
|
.tcx
|
||||||
|
.sess
|
||||||
|
.source_map()
|
||||||
|
.span_wrapped_by_angle_or_parentheses(ty.span) =>
|
||||||
|
{
|
||||||
|
format!("{deref_ty}")
|
||||||
|
}
|
||||||
_ => format!("<{deref_ty}>"),
|
_ => format!("<{deref_ty}>"),
|
||||||
};
|
};
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
@ -2576,8 +2597,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
|
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
|
||||||
// implement the `AsRef` trait.
|
// implement the `AsRef` trait.
|
||||||
let skip = skippable.contains(&did)
|
let skip = skippable.contains(&did)
|
||||||
|| (("Pin::new" == *pre) && ((sym::as_ref == item_name.name) || !unpin))
|
|| (("Pin::new" == *pre)
|
||||||
|| inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len);
|
&& ((sym::as_ref == item_name.name) || !unpin))
|
||||||
|
|| inputs_len.is_some_and(|inputs_len| {
|
||||||
|
pick.item.kind == ty::AssocKind::Fn
|
||||||
|
&& self
|
||||||
|
.tcx
|
||||||
|
.fn_sig(pick.item.def_id)
|
||||||
|
.skip_binder()
|
||||||
|
.skip_binder()
|
||||||
|
.inputs()
|
||||||
|
.len()
|
||||||
|
!= inputs_len
|
||||||
|
});
|
||||||
// Make sure the method is defined for the *actual* receiver: we don't
|
// Make sure the method is defined for the *actual* receiver: we don't
|
||||||
// want to treat `Box<Self>` as a receiver if it only works because of
|
// want to treat `Box<Self>` as a receiver if it only works because of
|
||||||
// an autoderef to `&self`
|
// an autoderef to `&self`
|
||||||
@ -2628,7 +2660,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// receiver has the same number of arguments that appear in the user's code.
|
// receiver has the same number of arguments that appear in the user's code.
|
||||||
&& inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
|
&& inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
|
||||||
{
|
{
|
||||||
let indent = self.tcx.sess
|
let indent = self
|
||||||
|
.tcx
|
||||||
|
.sess
|
||||||
.source_map()
|
.source_map()
|
||||||
.indentation_before(rcvr.span)
|
.indentation_before(rcvr.span)
|
||||||
.unwrap_or_else(|| " ".to_string());
|
.unwrap_or_else(|| " ".to_string());
|
||||||
@ -2995,14 +3029,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let parent = self.tcx.hir().parent_id(expr.hir_id);
|
let parent = self.tcx.hir().parent_id(expr.hir_id);
|
||||||
if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
|
if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent)
|
||||||
let hir::ExprKind::MethodCall(
|
&& let hir::ExprKind::MethodCall(
|
||||||
hir::PathSegment { ident: method_name, .. },
|
hir::PathSegment { ident: method_name, .. },
|
||||||
self_expr,
|
self_expr,
|
||||||
args,
|
args,
|
||||||
..,
|
..,
|
||||||
) = call_expr.kind &&
|
) = call_expr.kind
|
||||||
let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) {
|
&& let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr)
|
||||||
|
{
|
||||||
let new_name = Ident {
|
let new_name = Ident {
|
||||||
name: Symbol::intern(&format!("{}_else", method_name.as_str())),
|
name: Symbol::intern(&format!("{}_else", method_name.as_str())),
|
||||||
span: method_name.span,
|
span: method_name.span,
|
||||||
@ -3016,10 +3051,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// check the method arguments number
|
// check the method arguments number
|
||||||
if let Ok(pick) = probe &&
|
if let Ok(pick) = probe
|
||||||
let fn_sig = self.tcx.fn_sig(pick.item.def_id) &&
|
&& let fn_sig = self.tcx.fn_sig(pick.item.def_id)
|
||||||
let fn_args = fn_sig.skip_binder().skip_binder().inputs() &&
|
&& let fn_args = fn_sig.skip_binder().skip_binder().inputs()
|
||||||
fn_args.len() == args.len() + 1 {
|
&& fn_args.len() == args.len() + 1
|
||||||
|
{
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
method_name.span.shrink_to_hi(),
|
method_name.span.shrink_to_hi(),
|
||||||
format!("try calling `{}` instead", new_name.name.as_str()),
|
format!("try calling `{}` instead", new_name.name.as_str()),
|
||||||
|
@ -430,33 +430,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if let Some(lhs_new_mutbl) = lhs_new_mutbl
|
if let Some(lhs_new_mutbl) = lhs_new_mutbl
|
||||||
&& let Some(rhs_new_mutbl) = rhs_new_mutbl
|
&& let Some(rhs_new_mutbl) = rhs_new_mutbl
|
||||||
&& lhs_new_mutbl.is_not()
|
&& lhs_new_mutbl.is_not()
|
||||||
&& rhs_new_mutbl.is_not() {
|
&& rhs_new_mutbl.is_not()
|
||||||
|
{
|
||||||
err.multipart_suggestion_verbose(
|
err.multipart_suggestion_verbose(
|
||||||
"consider reborrowing both sides",
|
"consider reborrowing both sides",
|
||||||
vec![
|
vec![
|
||||||
(lhs_expr.span.shrink_to_lo(), "&*".to_string()),
|
(lhs_expr.span.shrink_to_lo(), "&*".to_string()),
|
||||||
(rhs_expr.span.shrink_to_lo(), "&*".to_string())
|
(rhs_expr.span.shrink_to_lo(), "&*".to_string()),
|
||||||
],
|
],
|
||||||
rustc_errors::Applicability::MachineApplicable,
|
rustc_errors::Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let mut suggest_new_borrow = |new_mutbl: ast::Mutability, sp: Span| {
|
let mut suggest_new_borrow =
|
||||||
// Can reborrow (&mut -> &)
|
|new_mutbl: ast::Mutability, sp: Span| {
|
||||||
if new_mutbl.is_not() {
|
// Can reborrow (&mut -> &)
|
||||||
err.span_suggestion_verbose(
|
if new_mutbl.is_not() {
|
||||||
sp.shrink_to_lo(),
|
err.span_suggestion_verbose(
|
||||||
"consider reborrowing this side",
|
sp.shrink_to_lo(),
|
||||||
"&*",
|
"consider reborrowing this side",
|
||||||
rustc_errors::Applicability::MachineApplicable,
|
"&*",
|
||||||
);
|
rustc_errors::Applicability::MachineApplicable,
|
||||||
// Works on &mut but have &
|
);
|
||||||
} else {
|
// Works on &mut but have &
|
||||||
err.span_help(
|
} else {
|
||||||
sp,
|
err.span_help(
|
||||||
"consider making this expression a mutable borrow",
|
sp,
|
||||||
);
|
"consider making this expression a mutable borrow",
|
||||||
}
|
);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(lhs_new_mutbl) = lhs_new_mutbl {
|
if let Some(lhs_new_mutbl) = lhs_new_mutbl {
|
||||||
suggest_new_borrow(lhs_new_mutbl, lhs_expr.span);
|
suggest_new_borrow(lhs_new_mutbl, lhs_expr.span);
|
||||||
@ -493,20 +495,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
} else if is_assign == IsAssign::No
|
} else if is_assign == IsAssign::No
|
||||||
&& let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind()
|
&& let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind()
|
||||||
{
|
{
|
||||||
if self.type_is_copy_modulo_regions(
|
if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty) {
|
||||||
self.param_env,
|
|
||||||
*lhs_deref_ty,
|
|
||||||
) {
|
|
||||||
suggest_deref_binop(&mut err, *lhs_deref_ty);
|
suggest_deref_binop(&mut err, *lhs_deref_ty);
|
||||||
} else {
|
} else {
|
||||||
let lhs_inv_mutbl = mutbl.invert();
|
let lhs_inv_mutbl = mutbl.invert();
|
||||||
let lhs_inv_mutbl_ty = Ty::new_ref(
|
let lhs_inv_mutbl_ty = Ty::new_ref(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
*region,
|
*region,
|
||||||
ty::TypeAndMut {
|
ty::TypeAndMut { ty: *lhs_deref_ty, mutbl: lhs_inv_mutbl },
|
||||||
ty: *lhs_deref_ty,
|
|
||||||
mutbl: lhs_inv_mutbl,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
suggest_different_borrow(
|
suggest_different_borrow(
|
||||||
@ -522,10 +518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let rhs_inv_mutbl_ty = Ty::new_ref(
|
let rhs_inv_mutbl_ty = Ty::new_ref(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
*region,
|
*region,
|
||||||
ty::TypeAndMut {
|
ty::TypeAndMut { ty: *rhs_deref_ty, mutbl: rhs_inv_mutbl },
|
||||||
ty: *rhs_deref_ty,
|
|
||||||
mutbl: rhs_inv_mutbl,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
suggest_different_borrow(
|
suggest_different_borrow(
|
||||||
@ -599,7 +592,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if let Some(output_def_id) = output_def_id
|
if let Some(output_def_id) = output_def_id
|
||||||
&& let Some(trait_def_id) = trait_def_id
|
&& let Some(trait_def_id) = trait_def_id
|
||||||
&& self.tcx.parent(output_def_id) == trait_def_id
|
&& self.tcx.parent(output_def_id) == trait_def_id
|
||||||
&& let Some(output_ty) = output_ty.make_suggestable(self.tcx, false)
|
&& let Some(output_ty) =
|
||||||
|
output_ty.make_suggestable(self.tcx, false)
|
||||||
{
|
{
|
||||||
Some(("Output", output_ty))
|
Some(("Output", output_ty))
|
||||||
} else {
|
} else {
|
||||||
|
@ -406,16 +406,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.treat_byte_string_as_slice
|
.treat_byte_string_as_slice
|
||||||
.insert(lt.hir_id.local_id);
|
.insert(lt.hir_id.local_id);
|
||||||
pat_ty = Ty::new_imm_ref(tcx,tcx.lifetimes.re_static, Ty::new_slice(tcx,tcx.types.u8));
|
pat_ty =
|
||||||
|
Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tcx.features().string_deref_patterns && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind {
|
if self.tcx.features().string_deref_patterns
|
||||||
|
&& let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind
|
||||||
|
{
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let expected = self.resolve_vars_if_possible(expected);
|
let expected = self.resolve_vars_if_possible(expected);
|
||||||
pat_ty = match expected.kind() {
|
pat_ty = match expected.kind() {
|
||||||
ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected,
|
ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected,
|
||||||
ty::Str => Ty::new_static_str(tcx,),
|
ty::Str => Ty::new_static_str(tcx),
|
||||||
_ => pat_ty,
|
_ => pat_ty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -707,7 +710,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
|
fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
if let PatKind::Ref(inner, mutbl) = pat.kind
|
if let PatKind::Ref(inner, mutbl) = pat.kind
|
||||||
&& let PatKind::Binding(_, _, binding, ..) = inner.kind {
|
&& let PatKind::Binding(_, _, binding, ..) = inner.kind
|
||||||
|
{
|
||||||
let binding_parent_id = tcx.hir().parent_id(pat.hir_id);
|
let binding_parent_id = tcx.hir().parent_id(pat.hir_id);
|
||||||
let binding_parent = tcx.hir().get(binding_parent_id);
|
let binding_parent = tcx.hir().get(binding_parent_id);
|
||||||
debug!(?inner, ?pat, ?binding_parent);
|
debug!(?inner, ?pat, ?binding_parent);
|
||||||
@ -754,7 +758,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
format!("to declare a mutable {ident_kind} use"),
|
format!("to declare a mutable {ident_kind} use"),
|
||||||
format!("mut {binding}"),
|
format!("mut {binding}"),
|
||||||
))
|
))
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match binding_parent {
|
match binding_parent {
|
||||||
@ -777,7 +780,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
|
hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
|
||||||
for i in pat_arr.iter() {
|
for i in pat_arr.iter() {
|
||||||
if let PatKind::Ref(the_ref, _) = i.kind
|
if let PatKind::Ref(the_ref, _) = i.kind
|
||||||
&& let PatKind::Binding(mt, _, ident, _) = the_ref.kind {
|
&& let PatKind::Binding(mt, _, ident, _) = the_ref.kind
|
||||||
|
{
|
||||||
let hir::BindingAnnotation(_, mtblty) = mt;
|
let hir::BindingAnnotation(_, mtblty) = mt;
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
i.span,
|
i.span,
|
||||||
@ -1480,7 +1484,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
(Some(mut err), None) => {
|
(Some(mut err), None) => {
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
(None, None) if let Some(mut err) =
|
(None, None)
|
||||||
|
if let Some(mut err) =
|
||||||
self.error_tuple_variant_index_shorthand(variant, pat, fields) =>
|
self.error_tuple_variant_index_shorthand(variant, pat, fields) =>
|
||||||
{
|
{
|
||||||
err.emit();
|
err.emit();
|
||||||
@ -2263,7 +2268,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&& let ty::Array(..) | ty::Slice(..) = ty.kind()
|
&& let ty::Array(..) | ty::Slice(..) = ty.kind()
|
||||||
{
|
{
|
||||||
err.help("the semantics of slice patterns changed recently; see issue #62254");
|
err.help("the semantics of slice patterns changed recently; see issue #62254");
|
||||||
} else if self.autoderef(span, expected_ty)
|
} else if self
|
||||||
|
.autoderef(span, expected_ty)
|
||||||
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
|
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
|
||||||
&& let Some(span) = ti.span
|
&& let Some(span) = ti.span
|
||||||
&& let Some(_) = ti.origin_expr
|
&& let Some(_) = ti.origin_expr
|
||||||
@ -2284,7 +2290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
if is_slice_or_array_or_vector.0 {
|
if is_slice_or_array_or_vector.0 {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
|
@ -174,7 +174,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprKind::AssignOp(..)
|
hir::ExprKind::AssignOp(..)
|
||||||
if let Some(a) = self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) =>
|
if let Some(a) =
|
||||||
|
self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) =>
|
||||||
{
|
{
|
||||||
a.pop();
|
a.pop();
|
||||||
}
|
}
|
||||||
@ -247,7 +248,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
// Since this is "after" the other adjustment to be
|
// Since this is "after" the other adjustment to be
|
||||||
// discarded, we do an extra `pop()`
|
// discarded, we do an extra `pop()`
|
||||||
if let Some(Adjustment {
|
if let Some(Adjustment {
|
||||||
kind: Adjust::Pointer(PointerCoercion::Unsize), ..
|
kind: Adjust::Pointer(PointerCoercion::Unsize),
|
||||||
|
..
|
||||||
}) = a.pop()
|
}) = a.pop()
|
||||||
{
|
{
|
||||||
// So the borrow discard actually happens here
|
// So the borrow discard actually happens here
|
||||||
@ -568,10 +570,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
|
|
||||||
// Here we only detect impl trait definition conflicts when they
|
// Here we only detect impl trait definition conflicts when they
|
||||||
// are equal modulo regions.
|
// are equal modulo regions.
|
||||||
if let Some(last_opaque_ty) = self
|
if let Some(last_opaque_ty) =
|
||||||
.typeck_results
|
self.typeck_results.concrete_opaque_types.insert(opaque_type_key, hidden_type)
|
||||||
.concrete_opaque_types
|
|
||||||
.insert(opaque_type_key, hidden_type)
|
|
||||||
&& last_opaque_ty.ty != hidden_type.ty
|
&& last_opaque_ty.ty != hidden_type.ty
|
||||||
{
|
{
|
||||||
assert!(!self.fcx.next_trait_solver());
|
assert!(!self.fcx.next_trait_solver());
|
||||||
|
@ -60,9 +60,7 @@ impl<'a> DescriptionCtx<'a> {
|
|||||||
let span = Some(tcx.def_span(scope));
|
let span = Some(tcx.def_span(scope));
|
||||||
(span, "defined_here", String::new())
|
(span, "defined_here", String::new())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()),
|
||||||
(Some(tcx.def_span(scope)), "defined_here_reg", region.to_string())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,8 +227,10 @@ fn msg_span_from_named_region<'tcx>(
|
|||||||
let scope = region.free_region_binding_scope(tcx).expect_local();
|
let scope = region.free_region_binding_scope(tcx).expect_local();
|
||||||
match fr.bound_region {
|
match fr.bound_region {
|
||||||
ty::BoundRegionKind::BrNamed(_, name) => {
|
ty::BoundRegionKind::BrNamed(_, name) => {
|
||||||
let span = if let Some(param) =
|
let span = if let Some(param) = tcx
|
||||||
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
|
.hir()
|
||||||
|
.get_generics(scope)
|
||||||
|
.and_then(|generics| generics.get_named(name))
|
||||||
{
|
{
|
||||||
param.span
|
param.span
|
||||||
} else {
|
} else {
|
||||||
@ -243,7 +245,7 @@ fn msg_span_from_named_region<'tcx>(
|
|||||||
}
|
}
|
||||||
ty::BrAnon => (
|
ty::BrAnon => (
|
||||||
"the anonymous lifetime as defined here".to_string(),
|
"the anonymous lifetime as defined here".to_string(),
|
||||||
Some(tcx.def_span(scope))
|
Some(tcx.def_span(scope)),
|
||||||
),
|
),
|
||||||
_ => (
|
_ => (
|
||||||
format!("the lifetime `{region}` as defined here"),
|
format!("the lifetime `{region}` as defined here"),
|
||||||
@ -715,13 +717,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
&& let ty::Adt(def, args) = ty.kind()
|
&& let ty::Adt(def, args) = ty.kind()
|
||||||
&& Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
|
&& Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
|
||||||
{
|
{
|
||||||
err.span_label(span, format!("this is an iterator with items of type `{}`", args.type_at(0)));
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!("this is an iterator with items of type `{}`", args.type_at(0)),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
err.span_label(span, format!("this expression has type `{ty}`"));
|
err.span_label(span, format!("this expression has type `{ty}`"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
|
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
|
||||||
&& ty.is_box() && ty.boxed_ty() == found
|
&& ty.is_box()
|
||||||
|
&& ty.boxed_ty() == found
|
||||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||||
{
|
{
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
@ -743,9 +749,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
||||||
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
|
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
|
||||||
let arg_expr = args.first().expect("try desugaring call w/out arg");
|
let arg_expr = args.first().expect("try desugaring call w/out arg");
|
||||||
self.typeck_results.as_ref().and_then(|typeck_results| {
|
self.typeck_results
|
||||||
typeck_results.expr_ty_opt(arg_expr)
|
.as_ref()
|
||||||
})
|
.and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr))
|
||||||
} else {
|
} else {
|
||||||
bug!("try desugaring w/out call expr as scrutinee");
|
bug!("try desugaring w/out call expr as scrutinee");
|
||||||
};
|
};
|
||||||
@ -763,7 +769,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||||
arm_block_id,
|
arm_block_id,
|
||||||
arm_span,
|
arm_span,
|
||||||
@ -782,9 +788,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
||||||
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
|
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
|
||||||
let arg_expr = args.first().expect("try desugaring call w/out arg");
|
let arg_expr = args.first().expect("try desugaring call w/out arg");
|
||||||
self.typeck_results.as_ref().and_then(|typeck_results| {
|
self.typeck_results
|
||||||
typeck_results.expr_ty_opt(arg_expr)
|
.as_ref()
|
||||||
})
|
.and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr))
|
||||||
} else {
|
} else {
|
||||||
bug!("try desugaring w/out call expr as scrutinee");
|
bug!("try desugaring w/out call expr as scrutinee");
|
||||||
};
|
};
|
||||||
@ -878,8 +884,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
// don't suggest wrapping either blocks in `if .. {} else {}`
|
// don't suggest wrapping either blocks in `if .. {} else {}`
|
||||||
let is_empty_arm = |id| {
|
let is_empty_arm = |id| {
|
||||||
let hir::Node::Block(blk) = self.tcx.hir().get(id)
|
let hir::Node::Block(blk) = self.tcx.hir().get(id) else {
|
||||||
else {
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if blk.expr.is_some() || !blk.stmts.is_empty() {
|
if blk.expr.is_some() || !blk.stmts.is_empty() {
|
||||||
@ -908,12 +913,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if let ObligationCauseCode::BindingObligation(_, span)
|
if let ObligationCauseCode::BindingObligation(_, span)
|
||||||
| ObligationCauseCode::ExprBindingObligation(_, span, ..)
|
| ObligationCauseCode::ExprBindingObligation(_, span, ..) =
|
||||||
= cause.code().peel_derives()
|
cause.code().peel_derives()
|
||||||
&& let TypeError::RegionsPlaceholderMismatch = terr
|
&& let TypeError::RegionsPlaceholderMismatch = terr
|
||||||
{
|
{
|
||||||
err.span_note( * span,
|
err.span_note(*span, "the lifetime requirement is introduced here");
|
||||||
"the lifetime requirement is introduced here");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1742,19 +1746,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
|
let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
|
||||||
if let ty::Adt(expected, _) = expected.kind() && let Some(primitive) = found.primitive_symbol() {
|
if let ty::Adt(expected, _) = expected.kind()
|
||||||
|
&& let Some(primitive) = found.primitive_symbol()
|
||||||
|
{
|
||||||
let path = self.tcx.def_path(expected.did()).data;
|
let path = self.tcx.def_path(expected.did()).data;
|
||||||
let name = path.last().unwrap().data.get_opt_name();
|
let name = path.last().unwrap().data.get_opt_name();
|
||||||
if name == Some(primitive) {
|
if name == Some(primitive) {
|
||||||
return Some(Similar::PrimitiveFound { expected: *expected, found });
|
return Some(Similar::PrimitiveFound { expected: *expected, found });
|
||||||
}
|
}
|
||||||
} else if let Some(primitive) = expected.primitive_symbol() && let ty::Adt(found, _) = found.kind() {
|
} else if let Some(primitive) = expected.primitive_symbol()
|
||||||
|
&& let ty::Adt(found, _) = found.kind()
|
||||||
|
{
|
||||||
let path = self.tcx.def_path(found.did()).data;
|
let path = self.tcx.def_path(found.did()).data;
|
||||||
let name = path.last().unwrap().data.get_opt_name();
|
let name = path.last().unwrap().data.get_opt_name();
|
||||||
if name == Some(primitive) {
|
if name == Some(primitive) {
|
||||||
return Some(Similar::PrimitiveExpected { expected, found: *found });
|
return Some(Similar::PrimitiveExpected { expected, found: *found });
|
||||||
}
|
}
|
||||||
} else if let ty::Adt(expected, _) = expected.kind() && let ty::Adt(found, _) = found.kind() {
|
} else if let ty::Adt(expected, _) = expected.kind()
|
||||||
|
&& let ty::Adt(found, _) = found.kind()
|
||||||
|
{
|
||||||
if !expected.did().is_local() && expected.did().krate == found.did().krate {
|
if !expected.did().is_local() && expected.did().krate == found.did().krate {
|
||||||
// Most likely types from different versions of the same crate
|
// Most likely types from different versions of the same crate
|
||||||
// are in play, in which case this message isn't so helpful.
|
// are in play, in which case this message isn't so helpful.
|
||||||
@ -1764,8 +1774,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
let f_path = self.tcx.def_path(found.did()).data;
|
let f_path = self.tcx.def_path(found.did()).data;
|
||||||
let e_path = self.tcx.def_path(expected.did()).data;
|
let e_path = self.tcx.def_path(expected.did()).data;
|
||||||
|
|
||||||
if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last()) && e_last == f_last {
|
if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last())
|
||||||
return Some(Similar::Adts{expected: *expected, found: *found});
|
&& e_last == f_last
|
||||||
|
{
|
||||||
|
return Some(Similar::Adts { expected: *expected, found: *found });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@ -1796,7 +1808,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let diagnose_adts =
|
let diagnose_adts =
|
||||||
|expected_adt : ty::AdtDef<'tcx>,
|
|expected_adt: ty::AdtDef<'tcx>,
|
||||||
found_adt: ty::AdtDef<'tcx>,
|
found_adt: ty::AdtDef<'tcx>,
|
||||||
diagnostic: &mut Diagnostic| {
|
diagnostic: &mut Diagnostic| {
|
||||||
let found_name = values.found.sort_string(self.tcx);
|
let found_name = values.found.sort_string(self.tcx);
|
||||||
@ -1816,8 +1828,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
.tcx
|
.tcx
|
||||||
.parent_module_from_def_id(defid.expect_local())
|
.parent_module_from_def_id(defid.expect_local())
|
||||||
.to_def_id();
|
.to_def_id();
|
||||||
let module_name = self.tcx.def_path(module).to_string_no_crate_verbose();
|
let module_name =
|
||||||
format!("{name} is defined in module `crate{module_name}` of the current crate")
|
self.tcx.def_path(module).to_string_no_crate_verbose();
|
||||||
|
format!(
|
||||||
|
"{name} is defined in module `crate{module_name}` of the current crate"
|
||||||
|
)
|
||||||
} else if defid.is_local() {
|
} else if defid.is_local() {
|
||||||
format!("{name} is defined in the current crate")
|
format!("{name} is defined in the current crate")
|
||||||
} else {
|
} else {
|
||||||
@ -1829,13 +1844,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match s {
|
match s {
|
||||||
Similar::Adts{expected, found} => {
|
Similar::Adts { expected, found } => diagnose_adts(expected, found, diag),
|
||||||
diagnose_adts(expected, found, diag)
|
Similar::PrimitiveFound { expected, found: prim } => {
|
||||||
}
|
|
||||||
Similar::PrimitiveFound{expected, found: prim} => {
|
|
||||||
diagnose_primitive(prim, values.expected, expected.did(), diag)
|
diagnose_primitive(prim, values.expected, expected.did(), diag)
|
||||||
}
|
}
|
||||||
Similar::PrimitiveExpected{expected: prim, found} => {
|
Similar::PrimitiveExpected { expected: prim, found } => {
|
||||||
diagnose_primitive(prim, values.found, found.did(), diag)
|
diagnose_primitive(prim, values.found, found.did(), diag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1877,7 +1890,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
s
|
s
|
||||||
};
|
};
|
||||||
if !(values.expected.is_simple_text(self.tcx) && values.found.is_simple_text(self.tcx))
|
if !(values.expected.is_simple_text(self.tcx)
|
||||||
|
&& values.found.is_simple_text(self.tcx))
|
||||||
|| (exp_found.is_some_and(|ef| {
|
|| (exp_found.is_some_and(|ef| {
|
||||||
// This happens when the type error is a subset of the expectation,
|
// This happens when the type error is a subset of the expectation,
|
||||||
// like when you have two references but one is `usize` and the other
|
// like when you have two references but one is `usize` and the other
|
||||||
@ -1967,13 +1981,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
&& let exp_found = TypeError::Sorts(exp_found)
|
&& let exp_found = TypeError::Sorts(exp_found)
|
||||||
&& exp_found != terr
|
&& exp_found != terr
|
||||||
{
|
{
|
||||||
self.note_and_explain_type_err(
|
self.note_and_explain_type_err(diag, exp_found, cause, span, cause.body_id.to_def_id());
|
||||||
diag,
|
|
||||||
exp_found,
|
|
||||||
cause,
|
|
||||||
span,
|
|
||||||
cause.body_id.to_def_id(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
|
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
|
||||||
@ -1983,7 +1991,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
{
|
{
|
||||||
let span = self.tcx.def_span(def_id);
|
let span = self.tcx.def_span(def_id);
|
||||||
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
|
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
|
||||||
self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag);
|
self.suggest_for_all_lifetime_closure(
|
||||||
|
span,
|
||||||
|
self.tcx.hir().get_by_def_id(def_id),
|
||||||
|
&exp_found,
|
||||||
|
diag,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// It reads better to have the error origin as the final
|
// It reads better to have the error origin as the final
|
||||||
@ -2009,7 +2022,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
// parentheses around it, perhaps the user meant to write `(expr,)` to
|
// parentheses around it, perhaps the user meant to write `(expr,)` to
|
||||||
// build a tuple (issue #86100)
|
// build a tuple (issue #86100)
|
||||||
(ty::Tuple(fields), _) => {
|
(ty::Tuple(fields), _) => {
|
||||||
suggestions.extend(self.suggest_wrap_to_build_a_tuple( span, found, fields))
|
suggestions.extend(self.suggest_wrap_to_build_a_tuple(span, found, fields))
|
||||||
}
|
}
|
||||||
// If a byte was expected and the found expression is a char literal
|
// If a byte was expected and the found expression is a char literal
|
||||||
// containing a single ASCII character, perhaps the user meant to write `b'c'` to
|
// containing a single ASCII character, perhaps the user meant to write `b'c'` to
|
||||||
@ -2059,8 +2072,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
// For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
|
// For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
|
||||||
// we try to suggest to add the missing `let` for `if let Some(..) = expr`
|
// we try to suggest to add the missing `let` for `if let Some(..) = expr`
|
||||||
(ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
|
(ty::Bool, ty::Tuple(list)) => {
|
||||||
suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
|
if list.len() == 0 {
|
||||||
|
suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(ty::Array(_, _), ty::Array(_, _)) => {
|
(ty::Array(_, _), ty::Array(_, _)) => {
|
||||||
suggestions.extend(self.suggest_specify_actual_length(terr, trace, span))
|
suggestions.extend(self.suggest_specify_actual_length(terr, trace, span))
|
||||||
@ -2070,8 +2085,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
let code = trace.cause.code();
|
let code = trace.cause.code();
|
||||||
if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. })
|
if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. })
|
||||||
| BlockTailExpression(.., source)
|
| BlockTailExpression(.., source)) = code
|
||||||
) = code
|
|
||||||
&& let hir::MatchSource::TryDesugar(_) = source
|
&& let hir::MatchSource::TryDesugar(_) = source
|
||||||
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
|
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
|
||||||
{
|
{
|
||||||
@ -2108,17 +2122,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
// Find a local statement where the initializer has
|
// Find a local statement where the initializer has
|
||||||
// the same span as the error and the type is specified.
|
// the same span as the error and the type is specified.
|
||||||
if let hir::Stmt {
|
if let hir::Stmt {
|
||||||
kind: hir::StmtKind::Local(hir::Local {
|
kind:
|
||||||
init: Some(hir::Expr {
|
hir::StmtKind::Local(hir::Local {
|
||||||
span: init_span,
|
init: Some(hir::Expr { span: init_span, .. }),
|
||||||
|
ty: Some(array_ty),
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
ty: Some(array_ty),
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
..
|
..
|
||||||
} = s
|
} = s
|
||||||
&& init_span == &self.span {
|
&& init_span == &self.span
|
||||||
|
{
|
||||||
self.result = Some(*array_ty);
|
self.result = Some(*array_ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,13 +163,13 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
|
|||||||
let ty_vars = infcx_inner.type_variables();
|
let ty_vars = infcx_inner.type_variables();
|
||||||
let var_origin = ty_vars.var_origin(ty_vid);
|
let var_origin = ty_vars.var_origin(ty_vid);
|
||||||
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind
|
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind
|
||||||
&& name != kw::SelfUpper && !var_origin.span.from_expansion()
|
&& name != kw::SelfUpper
|
||||||
|
&& !var_origin.span.from_expansion()
|
||||||
{
|
{
|
||||||
let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id));
|
let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id));
|
||||||
let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap();
|
let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap();
|
||||||
let generic_param_def = generics.param_at(idx as usize, infcx.tcx);
|
let generic_param_def = generics.param_at(idx as usize, infcx.tcx);
|
||||||
if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind
|
if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind {
|
||||||
{
|
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(name)
|
Some(name)
|
||||||
@ -792,8 +792,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
|||||||
let cost = self.source_cost(&new_source) + self.attempt;
|
let cost = self.source_cost(&new_source) + self.attempt;
|
||||||
debug!(?cost);
|
debug!(?cost);
|
||||||
self.attempt += 1;
|
self.attempt += 1;
|
||||||
if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source
|
if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, .. }, .. }) =
|
||||||
&& let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind
|
self.infer_source
|
||||||
|
&& let InferSourceKind::LetBinding { ref ty, ref mut def_id, .. } = new_source.kind
|
||||||
&& ty.is_ty_or_numeric_infer()
|
&& ty.is_ty_or_numeric_infer()
|
||||||
{
|
{
|
||||||
// Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
|
// Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
|
||||||
@ -1242,7 +1243,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
|
|||||||
successor,
|
successor,
|
||||||
args,
|
args,
|
||||||
def_id,
|
def_id,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||||||
ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
|
ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
|
||||||
_ => cause.code(),
|
_ => cause.code(),
|
||||||
}
|
}
|
||||||
&& let (&ObligationCauseCode::ItemObligation(item_def_id) | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), None) = (code, override_error_code)
|
&& let (
|
||||||
|
&ObligationCauseCode::ItemObligation(item_def_id)
|
||||||
|
| &ObligationCauseCode::ExprItemObligation(item_def_id, ..),
|
||||||
|
None,
|
||||||
|
) = (code, override_error_code)
|
||||||
{
|
{
|
||||||
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
|
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
|
||||||
// lifetime as above, but called using a fully-qualified path to the method:
|
// lifetime as above, but called using a fully-qualified path to the method:
|
||||||
@ -322,13 +326,27 @@ pub fn suggest_new_region_bound(
|
|||||||
let existing_lt_name = if let Some(id) = scope_def_id
|
let existing_lt_name = if let Some(id) = scope_def_id
|
||||||
&& let Some(generics) = tcx.hir().get_generics(id)
|
&& let Some(generics) = tcx.hir().get_generics(id)
|
||||||
&& let named_lifetimes = generics
|
&& let named_lifetimes = generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }))
|
.filter(|p| {
|
||||||
.map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}})
|
matches!(
|
||||||
.filter(|n| ! matches!(n, None))
|
p.kind,
|
||||||
.collect::<Vec<_>>()
|
GenericParamKind::Lifetime {
|
||||||
&& named_lifetimes.len() > 0 {
|
kind: hir::LifetimeParamKind::Explicit
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|p| {
|
||||||
|
if let hir::ParamName::Plain(name) = p.name {
|
||||||
|
Some(name.to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(|n| !matches!(n, None))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
&& named_lifetimes.len() > 0
|
||||||
|
{
|
||||||
named_lifetimes[0].clone()
|
named_lifetimes[0].clone()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -342,30 +360,28 @@ pub fn suggest_new_region_bound(
|
|||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|p| p.is_elided_lifetime())
|
.filter(|p| p.is_elided_lifetime())
|
||||||
.map(|p|
|
.map(|p| {
|
||||||
if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_)
|
if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) {
|
||||||
(p.span.shrink_to_hi(),format!("{name} "))
|
// Ampersand (elided without '_)
|
||||||
} else { // Underscore (elided with '_)
|
(p.span.shrink_to_hi(), format!("{name} "))
|
||||||
(p.span, name.to_string())
|
} else {
|
||||||
}
|
// Underscore (elided with '_)
|
||||||
)
|
(p.span, name.to_string())
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
&& spans_suggs.len() > 1
|
&& spans_suggs.len() > 1
|
||||||
{
|
{
|
||||||
let use_lt =
|
let use_lt = if existing_lt_name == None {
|
||||||
if existing_lt_name == None {
|
|
||||||
spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
|
spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
|
||||||
format!("you can introduce a named lifetime parameter `{name}`")
|
format!("you can introduce a named lifetime parameter `{name}`")
|
||||||
} else {
|
} else {
|
||||||
// make use the existing named lifetime
|
// make use the existing named lifetime
|
||||||
format!("you can use the named lifetime parameter `{name}`")
|
format!("you can use the named lifetime parameter `{name}`")
|
||||||
};
|
};
|
||||||
spans_suggs
|
spans_suggs.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
|
||||||
.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
|
|
||||||
err.multipart_suggestion_verbose(
|
err.multipart_suggestion_verbose(
|
||||||
format!(
|
format!("{declare} `{ty}` {captures}, {use_lt}",),
|
||||||
"{declare} `{ty}` {captures}, {use_lt}",
|
|
||||||
),
|
|
||||||
spans_suggs,
|
spans_suggs,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
@ -443,8 +459,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||||||
let trait_did = trait_id.to_def_id();
|
let trait_did = trait_id.to_def_id();
|
||||||
tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
|
tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
|
||||||
if let Node::Item(Item {
|
if let Node::Item(Item {
|
||||||
kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
|
kind: ItemKind::Impl(hir::Impl { self_ty, .. }), ..
|
||||||
..
|
|
||||||
}) = tcx.hir().find_by_def_id(impl_did)?
|
}) = tcx.hir().find_by_def_id(impl_did)?
|
||||||
&& trait_objects.iter().all(|did| {
|
&& trait_objects.iter().all(|did| {
|
||||||
// FIXME: we should check `self_ty` against the receiver
|
// FIXME: we should check `self_ty` against the receiver
|
||||||
|
@ -72,32 +72,30 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
#traits-as-parameters",
|
#traits-as-parameters",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
(ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => {
|
(
|
||||||
|
ty::Alias(ty::Projection | ty::Inherent, _),
|
||||||
|
ty::Alias(ty::Projection | ty::Inherent, _),
|
||||||
|
) => {
|
||||||
diag.note("an associated type was expected, but a different one was found");
|
diag.note("an associated type was expected, but a different one was found");
|
||||||
}
|
}
|
||||||
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
||||||
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
|
(ty::Param(p), ty::Alias(ty::Projection, proj))
|
||||||
|
| (ty::Alias(ty::Projection, proj), ty::Param(p))
|
||||||
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
|
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
|
||||||
{
|
{
|
||||||
let p_def_id = tcx
|
let p_def_id = tcx.generics_of(body_owner_def_id).type_param(p, tcx).def_id;
|
||||||
.generics_of(body_owner_def_id)
|
|
||||||
.type_param(p, tcx)
|
|
||||||
.def_id;
|
|
||||||
let p_span = tcx.def_span(p_def_id);
|
let p_span = tcx.def_span(p_def_id);
|
||||||
if !sp.contains(p_span) {
|
if !sp.contains(p_span) {
|
||||||
diag.span_label(p_span, "this type parameter");
|
diag.span_label(p_span, "this type parameter");
|
||||||
}
|
}
|
||||||
let hir = tcx.hir();
|
let hir = tcx.hir();
|
||||||
let mut note = true;
|
let mut note = true;
|
||||||
let parent = p_def_id
|
let parent = p_def_id.as_local().and_then(|id| {
|
||||||
.as_local()
|
let local_id = hir.local_def_id_to_hir_id(id);
|
||||||
.and_then(|id| {
|
let generics = tcx.hir().find_parent(local_id)?.generics()?;
|
||||||
let local_id = hir.local_def_id_to_hir_id(id);
|
Some((id, generics))
|
||||||
let generics = tcx.hir().find_parent(local_id)?.generics()?;
|
});
|
||||||
Some((id, generics))
|
if let Some((local_id, generics)) = parent {
|
||||||
});
|
|
||||||
if let Some((local_id, generics)) = parent
|
|
||||||
{
|
|
||||||
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
||||||
// FIXME: extract this logic for use in other diagnostics.
|
// FIXME: extract this logic for use in other diagnostics.
|
||||||
let (trait_ref, assoc_args) = proj.trait_ref_and_own_args(tcx);
|
let (trait_ref, assoc_args) = proj.trait_ref_and_own_args(tcx);
|
||||||
@ -112,15 +110,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
let mut matching_span = None;
|
let mut matching_span = None;
|
||||||
let mut matched_end_of_args = false;
|
let mut matched_end_of_args = false;
|
||||||
for bound in generics.bounds_for_param(local_id) {
|
for bound in generics.bounds_for_param(local_id) {
|
||||||
let potential_spans = bound
|
let potential_spans = bound.bounds.iter().find_map(|bound| {
|
||||||
.bounds
|
let bound_trait_path = bound.trait_ref()?.path;
|
||||||
.iter()
|
let def_id = bound_trait_path.res.opt_def_id()?;
|
||||||
.find_map(|bound| {
|
let generic_args = bound_trait_path
|
||||||
let bound_trait_path = bound.trait_ref()?.path;
|
.segments
|
||||||
let def_id = bound_trait_path.res.opt_def_id()?;
|
.iter()
|
||||||
let generic_args = bound_trait_path.segments.iter().last().map(|path| path.args());
|
.last()
|
||||||
(def_id == trait_ref.def_id).then_some((bound_trait_path.span, generic_args))
|
.map(|path| path.args());
|
||||||
});
|
(def_id == trait_ref.def_id)
|
||||||
|
.then_some((bound_trait_path.span, generic_args))
|
||||||
|
});
|
||||||
|
|
||||||
if let Some((end_of_trait, end_of_args)) = potential_spans {
|
if let Some((end_of_trait, end_of_args)) = potential_spans {
|
||||||
let args_span = end_of_args.and_then(|args| args.span());
|
let args_span = end_of_args.and_then(|args| args.span());
|
||||||
@ -223,7 +223,9 @@ impl<T> Trait<T> for X {
|
|||||||
diag.span_label(p_span, "this type parameter");
|
diag.span_label(p_span, "this type parameter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _)
|
||||||
|
if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
|
||||||
|
{
|
||||||
self.expected_projection(
|
self.expected_projection(
|
||||||
diag,
|
diag,
|
||||||
proj_ty,
|
proj_ty,
|
||||||
@ -232,11 +234,15 @@ impl<T> Trait<T> for X {
|
|||||||
cause.code(),
|
cause.code(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
(_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
(_, ty::Alias(ty::Projection | ty::Inherent, proj_ty))
|
||||||
let msg = || format!(
|
if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
|
||||||
"consider constraining the associated type `{}` to `{}`",
|
{
|
||||||
values.found, values.expected,
|
let msg = || {
|
||||||
);
|
format!(
|
||||||
|
"consider constraining the associated type `{}` to `{}`",
|
||||||
|
values.found, values.expected,
|
||||||
|
)
|
||||||
|
};
|
||||||
if !(self.suggest_constraining_opaque_associated_type(
|
if !(self.suggest_constraining_opaque_associated_type(
|
||||||
diag,
|
diag,
|
||||||
msg,
|
msg,
|
||||||
@ -256,19 +262,40 @@ impl<T> Trait<T> for X {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::Fn | DefKind::Static(_) | DefKind::Const | DefKind::AssocFn | DefKind::AssocConst) => {
|
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias))
|
||||||
|
if alias.def_id.is_local()
|
||||||
|
&& matches!(
|
||||||
|
tcx.def_kind(body_owner_def_id),
|
||||||
|
DefKind::Fn
|
||||||
|
| DefKind::Static(_)
|
||||||
|
| DefKind::Const
|
||||||
|
| DefKind::AssocFn
|
||||||
|
| DefKind::AssocConst
|
||||||
|
) =>
|
||||||
|
{
|
||||||
if tcx.is_type_alias_impl_trait(alias.def_id) {
|
if tcx.is_type_alias_impl_trait(alias.def_id) {
|
||||||
if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) {
|
if !tcx
|
||||||
let sp = tcx.def_ident_span(body_owner_def_id).unwrap_or_else(|| tcx.def_span(body_owner_def_id));
|
.opaque_types_defined_by(body_owner_def_id.expect_local())
|
||||||
diag.span_note(sp, "\
|
.contains(&alias.def_id.expect_local())
|
||||||
|
{
|
||||||
|
let sp = tcx
|
||||||
|
.def_ident_span(body_owner_def_id)
|
||||||
|
.unwrap_or_else(|| tcx.def_span(body_owner_def_id));
|
||||||
|
diag.span_note(
|
||||||
|
sp,
|
||||||
|
"\
|
||||||
this item must have the opaque type in its signature \
|
this item must have the opaque type in its signature \
|
||||||
in order to be able to register hidden types");
|
in order to be able to register hidden types",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ty::FnPtr(sig), ty::FnDef(def_id, _)) | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
|
(ty::FnPtr(sig), ty::FnDef(def_id, _))
|
||||||
|
| (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
|
||||||
if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() {
|
if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() {
|
||||||
diag.note("unsafe functions cannot be coerced into safe function pointers");
|
diag.note(
|
||||||
|
"unsafe functions cannot be coerced into safe function pointers",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -616,7 +643,8 @@ fn foo(&self) -> Self::T { String::new() }
|
|||||||
for item in &items[..] {
|
for item in &items[..] {
|
||||||
if let hir::AssocItemKind::Type = item.kind {
|
if let hir::AssocItemKind::Type = item.kind {
|
||||||
let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
|
let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
|
||||||
if let hir::Defaultness::Default { has_value: true } = tcx.defaultness(item.id.owner_id)
|
if let hir::Defaultness::Default { has_value: true } =
|
||||||
|
tcx.defaultness(item.id.owner_id)
|
||||||
&& self.infcx.can_eq(param_env, assoc_ty, found)
|
&& self.infcx.can_eq(param_env, assoc_ty, found)
|
||||||
{
|
{
|
||||||
diag.span_label(
|
diag.span_label(
|
||||||
|
@ -491,12 +491,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
|
|
||||||
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
|
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
|
||||||
if let hir::StmtKind::Local(hir::Local {
|
if let hir::StmtKind::Local(hir::Local {
|
||||||
span, pat: hir::Pat{..}, ty: None, init: Some(_), ..
|
span,
|
||||||
}) = &ex.kind
|
pat: hir::Pat { .. },
|
||||||
&& self.found_if
|
ty: None,
|
||||||
&& span.eq(&self.err_span) {
|
init: Some(_),
|
||||||
self.result = true;
|
..
|
||||||
}
|
}) = &ex.kind
|
||||||
|
&& self.found_if
|
||||||
|
&& span.eq(&self.err_span)
|
||||||
|
{
|
||||||
|
self.result = true;
|
||||||
|
}
|
||||||
walk_stmt(self, ex);
|
walk_stmt(self, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,45 +551,59 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
let expected = expected.unpack();
|
let expected = expected.unpack();
|
||||||
let found = found.unpack();
|
let found = found.unpack();
|
||||||
// 3. Extract the tuple type from Fn trait and suggest the change.
|
// 3. Extract the tuple type from Fn trait and suggest the change.
|
||||||
if let GenericArgKind::Type(expected) = expected &&
|
if let GenericArgKind::Type(expected) = expected
|
||||||
let GenericArgKind::Type(found) = found &&
|
&& let GenericArgKind::Type(found) = found
|
||||||
let ty::Tuple(expected) = expected.kind() &&
|
&& let ty::Tuple(expected) = expected.kind()
|
||||||
let ty::Tuple(found)= found.kind() &&
|
&& let ty::Tuple(found) = found.kind()
|
||||||
expected.len() == found.len() {
|
&& expected.len() == found.len()
|
||||||
|
{
|
||||||
let mut suggestion = "|".to_string();
|
let mut suggestion = "|".to_string();
|
||||||
let mut is_first = true;
|
let mut is_first = true;
|
||||||
let mut has_suggestion = false;
|
let mut has_suggestion = false;
|
||||||
|
|
||||||
for (((expected, found), param_hir), arg_hir) in expected.iter()
|
for (((expected, found), param_hir), arg_hir) in
|
||||||
.zip(found.iter())
|
expected.iter().zip(found.iter()).zip(params.iter()).zip(fn_decl.inputs.iter())
|
||||||
.zip(params.iter())
|
{
|
||||||
.zip(fn_decl.inputs.iter()) {
|
|
||||||
if is_first {
|
if is_first {
|
||||||
is_first = false;
|
is_first = false;
|
||||||
} else {
|
} else {
|
||||||
suggestion += ", ";
|
suggestion += ", ";
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ty::Ref(expected_region, _, _) = expected.kind() &&
|
if let ty::Ref(expected_region, _, _) = expected.kind()
|
||||||
let ty::Ref(found_region, _, _) = found.kind() &&
|
&& let ty::Ref(found_region, _, _) = found.kind()
|
||||||
expected_region.is_late_bound() &&
|
&& expected_region.is_late_bound()
|
||||||
!found_region.is_late_bound() &&
|
&& !found_region.is_late_bound()
|
||||||
let hir::TyKind::Infer = arg_hir.kind {
|
&& let hir::TyKind::Infer = arg_hir.kind
|
||||||
|
{
|
||||||
// If the expected region is late bound, the found region is not, and users are asking compiler
|
// If the expected region is late bound, the found region is not, and users are asking compiler
|
||||||
// to infer the type, we can suggest adding `: &_`.
|
// to infer the type, we can suggest adding `: &_`.
|
||||||
if param_hir.pat.span == param_hir.ty_span {
|
if param_hir.pat.span == param_hir.ty_span {
|
||||||
// for `|x|`, `|_|`, `|x: impl Foo|`
|
// for `|x|`, `|_|`, `|x: impl Foo|`
|
||||||
let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
|
let Ok(pat) =
|
||||||
|
self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
suggestion += &format!("{pat}: &_");
|
suggestion += &format!("{pat}: &_");
|
||||||
} else {
|
} else {
|
||||||
// for `|x: ty|`, `|_: ty|`
|
// for `|x: ty|`, `|_: ty|`
|
||||||
let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
|
let Ok(pat) =
|
||||||
let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; };
|
self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
suggestion += &format!("{pat}: &{ty}");
|
suggestion += &format!("{pat}: &{ty}");
|
||||||
}
|
}
|
||||||
has_suggestion = true;
|
has_suggestion = true;
|
||||||
} else {
|
} else {
|
||||||
let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; };
|
let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
// Otherwise, keep it as-is.
|
// Otherwise, keep it as-is.
|
||||||
suggestion += &arg;
|
suggestion += &arg;
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||||
if let ty::ReVar(vid) = *r && self.region_vars.0.contains(&vid) {
|
if let ty::ReVar(vid) = *r
|
||||||
|
&& self.region_vars.0.contains(&vid)
|
||||||
|
{
|
||||||
let idx = vid.index() - self.region_vars.0.start.index();
|
let idx = vid.index() - self.region_vars.0.start.index();
|
||||||
let origin = self.region_vars.1[idx];
|
let origin = self.region_vars.1[idx];
|
||||||
return self.infcx.next_region_var(origin);
|
return self.infcx.next_region_var(origin);
|
||||||
|
@ -346,7 +346,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||||||
// tighter bound than `'static`.
|
// tighter bound than `'static`.
|
||||||
//
|
//
|
||||||
// (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
|
// (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
|
||||||
if let ty::RePlaceholder(p) = *lub && b_universe.cannot_name(p.universe) {
|
if let ty::RePlaceholder(p) = *lub
|
||||||
|
&& b_universe.cannot_name(p.universe)
|
||||||
|
{
|
||||||
lub = self.tcx().lifetimes.re_static;
|
lub = self.tcx().lifetimes.re_static;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +177,9 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
|
|||||||
value: ty::Region<'tcx>,
|
value: ty::Region<'tcx>,
|
||||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||||
debug!("self.pattern_depth = {:?}", self.pattern_depth);
|
debug!("self.pattern_depth = {:?}", self.pattern_depth);
|
||||||
if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() && depth == self.pattern_depth {
|
if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind()
|
||||||
|
&& depth == self.pattern_depth
|
||||||
|
{
|
||||||
self.bind(br, value)
|
self.bind(br, value)
|
||||||
} else if pattern == value {
|
} else if pattern == value {
|
||||||
Ok(pattern)
|
Ok(pattern)
|
||||||
|
@ -108,20 +108,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||||||
let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
|
let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
|
||||||
|
|
||||||
// Search the env for where clauses like `P: 'a`.
|
// Search the env for where clauses like `P: 'a`.
|
||||||
let env_bounds = self
|
let env_bounds = self.approx_declared_bounds_from_env(alias_ty).into_iter().map(|binder| {
|
||||||
.approx_declared_bounds_from_env(alias_ty)
|
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars()
|
||||||
.into_iter()
|
&& ty == alias_ty_as_ty
|
||||||
.map(|binder| {
|
{
|
||||||
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty {
|
// Micro-optimize if this is an exact match (this
|
||||||
// Micro-optimize if this is an exact match (this
|
// occurs often when there are no region variables
|
||||||
// occurs often when there are no region variables
|
// involved).
|
||||||
// involved).
|
VerifyBound::OutlivedBy(r)
|
||||||
VerifyBound::OutlivedBy(r)
|
} else {
|
||||||
} else {
|
let verify_if_eq_b =
|
||||||
let verify_if_eq_b = binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
|
binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
|
||||||
VerifyBound::IfEq(verify_if_eq_b)
|
VerifyBound::IfEq(verify_if_eq_b)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Extend with bounds that we can find from the definition.
|
// Extend with bounds that we can find from the definition.
|
||||||
let definition_bounds =
|
let definition_bounds =
|
||||||
|
@ -457,7 +457,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
|||||||
debug!("RegionConstraintCollector: add_verify({:?})", verify);
|
debug!("RegionConstraintCollector: add_verify({:?})", verify);
|
||||||
|
|
||||||
// skip no-op cases known to be satisfied
|
// skip no-op cases known to be satisfied
|
||||||
if let VerifyBound::AllBounds(ref bs) = verify.bound && bs.is_empty() {
|
if let VerifyBound::AllBounds(ref bs) = verify.bound
|
||||||
|
&& bs.is_empty()
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,9 @@ pub fn report_object_safety_error<'tcx>(
|
|||||||
let mut multi_span = vec![];
|
let mut multi_span = vec![];
|
||||||
let mut messages = vec![];
|
let mut messages = vec![];
|
||||||
for violation in violations {
|
for violation in violations {
|
||||||
if let ObjectSafetyViolation::SizedSelf(sp) = &violation && !sp.is_empty() {
|
if let ObjectSafetyViolation::SizedSelf(sp) = &violation
|
||||||
|
&& !sp.is_empty()
|
||||||
|
{
|
||||||
// Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
|
// Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
|
||||||
// with a `Span`.
|
// with a `Span`.
|
||||||
reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into()));
|
reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into()));
|
||||||
|
@ -117,9 +117,12 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
|
|||||||
def.owner_id.def_id,
|
def.owner_id.def_id,
|
||||||
" + Send",
|
" + Send",
|
||||||
);
|
);
|
||||||
cx.tcx.emit_spanned_lint(ASYNC_FN_IN_TRAIT, item.hir_id(), async_span, AsyncFnInTraitDiag {
|
cx.tcx.emit_spanned_lint(
|
||||||
sugg
|
ASYNC_FN_IN_TRAIT,
|
||||||
});
|
item.hir_id(),
|
||||||
|
async_span,
|
||||||
|
AsyncFnInTraitDiag { sugg },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,16 +121,14 @@ impl EarlyLintPass for WhileTrue {
|
|||||||
{
|
{
|
||||||
let condition_span = e.span.with_hi(cond.span.hi());
|
let condition_span = e.span.with_hi(cond.span.hi());
|
||||||
let replace = format!(
|
let replace = format!(
|
||||||
"{}loop",
|
"{}loop",
|
||||||
label.map_or_else(String::new, |label| format!(
|
label.map_or_else(String::new, |label| format!("{}: ", label.ident,))
|
||||||
"{}: ",
|
);
|
||||||
label.ident,
|
cx.emit_spanned_lint(
|
||||||
))
|
WHILE_TRUE,
|
||||||
);
|
condition_span,
|
||||||
cx.emit_spanned_lint(WHILE_TRUE, condition_span, BuiltinWhileTrue {
|
BuiltinWhileTrue { suggestion: condition_span, replace },
|
||||||
suggestion: condition_span,
|
);
|
||||||
replace,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +162,9 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
|
|||||||
impl BoxPointers {
|
impl BoxPointers {
|
||||||
fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
|
fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
|
||||||
for leaf in ty.walk() {
|
for leaf in ty.walk() {
|
||||||
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && leaf_ty.is_box() {
|
if let GenericArgKind::Type(leaf_ty) = leaf.unpack()
|
||||||
|
&& leaf_ty.is_box()
|
||||||
|
{
|
||||||
cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
|
cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -681,7 +681,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
|
|||||||
// We shouldn't recommend implementing `Copy` on stateful things,
|
// We shouldn't recommend implementing `Copy` on stateful things,
|
||||||
// such as iterators.
|
// such as iterators.
|
||||||
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
|
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
|
||||||
&& cx.tcx
|
&& cx
|
||||||
|
.tcx
|
||||||
.infer_ctxt()
|
.infer_ctxt()
|
||||||
.build()
|
.build()
|
||||||
.type_implements_trait(iter_trait, [ty], param_env)
|
.type_implements_trait(iter_trait, [ty], param_env)
|
||||||
@ -1298,10 +1299,14 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
|
|||||||
// Now, check if the function has the `#[track_caller]` attribute
|
// Now, check if the function has the `#[track_caller]` attribute
|
||||||
&& let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
|
&& let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
|
||||||
{
|
{
|
||||||
cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller {
|
cx.emit_spanned_lint(
|
||||||
label: span,
|
UNGATED_ASYNC_FN_TRACK_CALLER,
|
||||||
parse_sess: &cx.tcx.sess.parse_sess,
|
attr.span,
|
||||||
});
|
BuiltinUngatedAsyncFnTrackCaller {
|
||||||
|
label: span,
|
||||||
|
parse_sess: &cx.tcx.sess.parse_sess,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user