Skip to content

Commit

Permalink
Auto merge of rust-lang#87698 - camsteffen:rollup-yvjfc26, r=camsteffen
Browse files Browse the repository at this point in the history
Rollup of 6 pull requests

Successful merges:

 - rust-lang#86176 (Implement a `explicit_generic_args_with_impl_trait` feature gate)
 - rust-lang#87654 (Add documentation for the order of Option and Result)
 - rust-lang#87659 (Fix invalid suggestions for non-ASCII characters in byte constants)
 - rust-lang#87673 (Tweak opaque type mismatch error)
 - rust-lang#87687 (Inline some macros)
 - rust-lang#87690 (Add missing "allocated object" doc link to `<*mut T>::add`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Aug 2, 2021
2 parents 3227e35 + 7fc26e9 commit 6be8a06
Show file tree
Hide file tree
Showing 32 changed files with 437 additions and 170 deletions.
16 changes: 4 additions & 12 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
// -------------------------------------------------------------------------
Expand Down
68 changes: 43 additions & 25 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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),
),
);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
37 changes: 29 additions & 8 deletions compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ symbols! {
expected,
expf32,
expf64,
explicit_generic_args_with_impl_trait,
export_name,
expr,
extended_key_value_attributes,
Expand Down
35 changes: 32 additions & 3 deletions compiler/rustc_typeck/src/astconv/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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,
Expand All @@ -630,7 +659,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
});

if explicit && impl_trait {
if impl_trait {
let spans = seg
.args()
.args
Expand Down
100 changes: 49 additions & 51 deletions compiler/rustc_typeck/src/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
13 changes: 13 additions & 0 deletions library/core/src/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,19 @@
//! assert_eq!(res, ["error!", "error!", "foo", "error!", "bar"]);
//! ```
//!
//! ## Comparison operators
//!
//! If `T` implements [`PartialOrd`] then [`Option<T>`] will derive its
//! [`PartialOrd`] implementation. With this order, [`None`] compares as
//! less than any [`Some`], and two [`Some`] compare the same way as their
//! contained values would in `T`. If `T` also implements
//! [`Ord`], then so does [`Option<T>`].
//!
//! ```
//! assert!(None < Some(0));
//! assert!(Some(0) < Some(1));
//! ```
//!
//! ## Iterating over `Option`
//!
//! An [`Option`] can be iterated over. This can be helpful if you need an
Expand Down

0 comments on commit 6be8a06

Please sign in to comment.