Auto merge of #87698 - camsteffen:rollup-yvjfc26, r=camsteffen
Rollup of 6 pull requests Successful merges: - #86176 (Implement a `explicit_generic_args_with_impl_trait` feature gate) - #87654 (Add documentation for the order of Option and Result) - #87659 (Fix invalid suggestions for non-ASCII characters in byte constants) - #87673 (Tweak opaque type mismatch error) - #87687 (Inline some macros) - #87690 (Add missing "allocated object" doc link to `<*mut T>::add`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6be8a06bcf
32 changed files with 437 additions and 170 deletions
|
@ -442,18 +442,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
then: &Block,
|
||||
else_opt: Option<&Expr>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
macro_rules! make_if {
|
||||
($opt:expr) => {{
|
||||
let cond = self.lower_expr(cond);
|
||||
let then_expr = self.lower_block_expr(then);
|
||||
hir::ExprKind::If(cond, self.arena.alloc(then_expr), $opt)
|
||||
}};
|
||||
}
|
||||
if let Some(rslt) = else_opt {
|
||||
make_if!(Some(self.lower_expr(rslt)))
|
||||
} else {
|
||||
make_if!(None)
|
||||
}
|
||||
let cond = self.lower_expr(cond);
|
||||
let then = self.arena.alloc(self.lower_block_expr(then));
|
||||
let els = else_opt.map(|els| self.lower_expr(els));
|
||||
hir::ExprKind::If(cond, then, els)
|
||||
}
|
||||
|
||||
fn lower_expr_if_let(
|
||||
|
|
|
@ -687,6 +687,9 @@ declare_features! (
|
|||
/// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
|
||||
(incomplete, trait_upcasting, "1.56.0", Some(65991), None),
|
||||
|
||||
/// Allows explicit generic arguments specification with `impl Trait` present.
|
||||
(active, explicit_generic_args_with_impl_trait, "1.56.0", Some(83701), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
@ -71,7 +71,7 @@ use rustc_middle::ty::{
|
|||
subst::{GenericArgKind, Subst, SubstsRef},
|
||||
Region, Ty, TyCtxt, TypeFoldable,
|
||||
};
|
||||
use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
|
||||
use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
|
||||
use rustc_target::spec::abi;
|
||||
use std::ops::ControlFlow;
|
||||
use std::{cmp, fmt, iter};
|
||||
|
@ -1485,31 +1485,49 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
let count = values.len();
|
||||
let kind = key.descr();
|
||||
let mut returned_async_output_error = false;
|
||||
for sp in values {
|
||||
err.span_label(
|
||||
*sp,
|
||||
format!(
|
||||
"{}{}{} {}{}",
|
||||
if sp.is_desugaring(DesugaringKind::Async)
|
||||
&& !returned_async_output_error
|
||||
{
|
||||
"checked the `Output` of this `async fn`, "
|
||||
} else if count == 1 {
|
||||
"the "
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if count > 1 { "one of the " } else { "" },
|
||||
target,
|
||||
kind,
|
||||
pluralize!(count),
|
||||
),
|
||||
);
|
||||
if sp.is_desugaring(DesugaringKind::Async)
|
||||
&& returned_async_output_error == false
|
||||
{
|
||||
err.note("while checking the return type of the `async fn`");
|
||||
for &sp in values {
|
||||
if sp.is_desugaring(DesugaringKind::Async) && !returned_async_output_error {
|
||||
if &[sp] != err.span.primary_spans() {
|
||||
let mut span: MultiSpan = sp.into();
|
||||
span.push_span_label(
|
||||
sp,
|
||||
format!(
|
||||
"checked the `Output` of this `async fn`, {}{} {}{}",
|
||||
if count > 1 { "one of the " } else { "" },
|
||||
target,
|
||||
kind,
|
||||
pluralize!(count),
|
||||
),
|
||||
);
|
||||
err.span_note(
|
||||
span,
|
||||
"while checking the return type of the `async fn`",
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
sp,
|
||||
format!(
|
||||
"checked the `Output` of this `async fn`, {}{} {}{}",
|
||||
if count > 1 { "one of the " } else { "" },
|
||||
target,
|
||||
kind,
|
||||
pluralize!(count),
|
||||
),
|
||||
);
|
||||
err.note("while checking the return type of the `async fn`");
|
||||
}
|
||||
returned_async_output_error = true;
|
||||
} else {
|
||||
err.span_label(
|
||||
sp,
|
||||
format!(
|
||||
"{}{} {}{}",
|
||||
if count == 1 { "the " } else { "one of the " },
|
||||
target,
|
||||
kind,
|
||||
pluralize!(count),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -769,7 +769,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
// (#83606): Do not emit a suggestion if the parent has an `impl Trait`
|
||||
// as an argument otherwise it will cause the E0282 error.
|
||||
if !has_impl_trait {
|
||||
if !has_impl_trait || self.tcx.features().explicit_generic_args_with_impl_trait {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
"consider specifying the const argument",
|
||||
|
|
|
@ -153,16 +153,37 @@ pub(crate) fn emit_unescape_error(
|
|||
EscapeError::NonAsciiCharInByte => {
|
||||
assert!(mode.is_bytes());
|
||||
let (c, span) = last_char();
|
||||
handler
|
||||
.struct_span_err(span, "non-ASCII character in byte constant")
|
||||
.span_label(span, "byte constant must be ASCII")
|
||||
.span_suggestion(
|
||||
let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant");
|
||||
err.span_label(span, "byte constant must be ASCII");
|
||||
if (c as u32) <= 0xFF {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"use a \\xHH escape for a non-ASCII byte",
|
||||
&format!(
|
||||
"if you meant to use the unicode code point for '{}', use a \\xHH escape",
|
||||
c
|
||||
),
|
||||
format!("\\x{:X}", c as u32),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if matches!(mode, Mode::Byte) {
|
||||
err.span_label(span, "this multibyte character does not fit into a single byte");
|
||||
} else if matches!(mode, Mode::ByteStr) {
|
||||
let mut utf8 = String::new();
|
||||
utf8.push(c);
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&format!(
|
||||
"if you meant to use the UTF-8 encoding of '{}', use \\xHH escapes",
|
||||
c
|
||||
),
|
||||
utf8.as_bytes()
|
||||
.iter()
|
||||
.map(|b: &u8| format!("\\x{:X}", *b))
|
||||
.fold("".to_string(), |a, c| a + &c),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
EscapeError::NonAsciiCharInByteString => {
|
||||
assert!(mode.is_bytes());
|
||||
|
|
|
@ -554,6 +554,7 @@ symbols! {
|
|||
expected,
|
||||
expf32,
|
||||
expf64,
|
||||
explicit_generic_args_with_impl_trait,
|
||||
export_name,
|
||||
expr,
|
||||
extended_key_value_attributes,
|
||||
|
|
|
@ -459,7 +459,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
let default_counts = gen_params.own_defaults();
|
||||
let param_counts = gen_params.own_counts();
|
||||
let named_type_param_count = param_counts.types - has_self as usize;
|
||||
|
||||
// Subtracting from param count to ensure type params synthesized from `impl Trait`
|
||||
// cannot be explictly specified even with `explicit_generic_args_with_impl_trait`
|
||||
// feature enabled.
|
||||
let synth_type_param_count = if tcx.features().explicit_generic_args_with_impl_trait {
|
||||
gen_params
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(
|
||||
param.kind,
|
||||
ty::GenericParamDefKind::Type {
|
||||
synthetic: Some(
|
||||
hir::SyntheticTyParamKind::ImplTrait
|
||||
| hir::SyntheticTyParamKind::FromAttr
|
||||
),
|
||||
..
|
||||
}
|
||||
)
|
||||
})
|
||||
.count()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let named_type_param_count =
|
||||
param_counts.types - has_self as usize - synth_type_param_count;
|
||||
let infer_lifetimes =
|
||||
gen_pos != GenericArgPosition::Type && !gen_args.has_lifetime_params();
|
||||
|
||||
|
@ -588,6 +613,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
param_counts.consts + named_type_param_count
|
||||
- default_counts.types
|
||||
- default_counts.consts
|
||||
- synth_type_param_count
|
||||
};
|
||||
debug!("expected_min: {:?}", expected_min);
|
||||
debug!("arg_counts.lifetimes: {:?}", gen_args.num_lifetime_params());
|
||||
|
@ -617,7 +643,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
seg: &hir::PathSegment<'_>,
|
||||
generics: &ty::Generics,
|
||||
) -> bool {
|
||||
let explicit = !seg.infer_args;
|
||||
if seg.infer_args || tcx.features().explicit_generic_args_with_impl_trait {
|
||||
return false;
|
||||
}
|
||||
|
||||
let impl_trait = generics.params.iter().any(|param| {
|
||||
matches!(
|
||||
param.kind,
|
||||
|
@ -630,7 +659,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
)
|
||||
});
|
||||
|
||||
if explicit && impl_trait {
|
||||
if impl_trait {
|
||||
let spans = seg
|
||||
.args()
|
||||
.args
|
||||
|
|
|
@ -13,41 +13,6 @@ use rustc_trait_selection::traits::{
|
|||
StatementAsExpression,
|
||||
};
|
||||
|
||||
macro_rules! create_maybe_get_coercion_reason {
|
||||
($fn_name:ident, $node:expr) => {
|
||||
pub(crate) fn $fn_name(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> {
|
||||
let node = $node(self.tcx.hir(), hir_id);
|
||||
if let hir::Node::Block(block) = node {
|
||||
// check that the body's parent is an fn
|
||||
let parent = self.tcx.hir().get(
|
||||
self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(block.hir_id)),
|
||||
);
|
||||
if let (
|
||||
Some(expr),
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }),
|
||||
) = (&block.expr, parent)
|
||||
{
|
||||
// check that the `if` expr without `else` is the fn body's expr
|
||||
if expr.span == sp {
|
||||
return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
|
||||
let span = fn_decl.output.span();
|
||||
let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
|
||||
Some((
|
||||
span,
|
||||
format!("expected `{}` because of this return type", snippet),
|
||||
))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if let hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) = node {
|
||||
return Some((pat.span, "expected because of this assignment".to_string()));
|
||||
}
|
||||
None
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub fn check_match(
|
||||
&self,
|
||||
|
@ -154,7 +119,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expr.span,
|
||||
&arms[0].body,
|
||||
&mut coercion,
|
||||
|hir_id, span| self.maybe_get_coercion_reason(hir_id, span),
|
||||
|hir_id, span| self.coercion_reason_match(hir_id, span),
|
||||
) {
|
||||
tcx.ty_error()
|
||||
} else {
|
||||
|
@ -373,23 +338,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
error
|
||||
}
|
||||
|
||||
create_maybe_get_coercion_reason!(
|
||||
maybe_get_coercion_reason,
|
||||
|hir: rustc_middle::hir::map::Map<'a>, id| {
|
||||
let arm_id = hir.get_parent_node(id);
|
||||
let match_id = hir.get_parent_node(arm_id);
|
||||
let containing_id = hir.get_parent_node(match_id);
|
||||
hir.get(containing_id)
|
||||
}
|
||||
);
|
||||
pub(crate) fn coercion_reason_if(
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
) -> Option<(Span, String)> {
|
||||
self.coercion_reason_inner(hir_id, span, 1)
|
||||
}
|
||||
|
||||
create_maybe_get_coercion_reason!(
|
||||
maybe_get_coercion_reason_if,
|
||||
|hir: rustc_middle::hir::map::Map<'a>, id| {
|
||||
let rslt = hir.get_parent_node(hir.get_parent_node(id));
|
||||
hir.get(rslt)
|
||||
pub(crate) fn coercion_reason_match(
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
) -> Option<(Span, String)> {
|
||||
self.coercion_reason_inner(hir_id, span, 2)
|
||||
}
|
||||
|
||||
fn coercion_reason_inner(
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
parent_index: usize,
|
||||
) -> Option<(Span, String)> {
|
||||
let hir = self.tcx.hir();
|
||||
let mut parent_iter = hir.parent_iter(hir_id);
|
||||
let (_, node) = parent_iter.nth(parent_index)?;
|
||||
match node {
|
||||
hir::Node::Block(block) => {
|
||||
let expr = block.expr?;
|
||||
// check that the body's parent is an fn
|
||||
let (_, parent) = parent_iter.nth(1)?;
|
||||
if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) = parent {
|
||||
// check that the `if` expr without `else` is the fn body's expr
|
||||
if expr.span == span {
|
||||
let (fn_decl, _) = self.get_fn_decl(hir_id)?;
|
||||
let span = fn_decl.output.span();
|
||||
let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
|
||||
return Some((
|
||||
span,
|
||||
format!("expected `{}` because of this return type", snippet),
|
||||
));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) => {
|
||||
Some((pat.span, "expected because of this assignment".to_string()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn if_cause(
|
||||
&self,
|
||||
|
|
|
@ -838,7 +838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.diverges.set(cond_diverges | then_diverges & else_diverges);
|
||||
} else {
|
||||
self.if_fallback_coercion(sp, then_expr, &mut coerce, |hir_id, span| {
|
||||
self.maybe_get_coercion_reason_if(hir_id, span)
|
||||
self.coercion_reason_if(hir_id, span)
|
||||
});
|
||||
|
||||
// If the condition is false we can't diverge.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue