Auto merge of #121169 - GuillaumeGomez:rollup-oxk5d5j, r=GuillaumeGomez

Rollup of 10 pull requests

Successful merges:

 - #120777 (Bump Unicode to version 15.1.0, regenerate tables)
 - #120971 (Fix comment in core/src/str/validations.rs)
 - #121095 (Add extra indent spaces for rust-playground link)
 - #121109 (Add an ErrorGuaranteed to ast::TyKind::Err (attempt 2))
 - #121119 (Make `async Fn` trait kind errors better)
 - #121141 (Fix closure kind docs)
 - #121145 (Update aarch64 target feature docs to match LLVM)
 - #121146 (Only point out non-diverging arms for match suggestions)
 - #121147 (Avoid debug logging entire MIR body)
 - #121155 (doc: add note about panicking examples for strict_overflow_ops)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-02-16 00:03:46 +00:00
commit cefa14bf2f
43 changed files with 484 additions and 156 deletions

View File

@ -2136,10 +2136,12 @@ pub enum TyKind {
ImplicitSelf,
/// A macro in the type position.
MacCall(P<MacCall>),
/// Placeholder for a kind that has failed to be defined.
Err,
/// Placeholder for a `va_list`.
CVarArgs,
/// Sometimes we need a dummy value when no error has occurred.
Dummy,
/// Placeholder for a kind that has failed to be defined.
Err(ErrorGuaranteed),
}
impl TyKind {

View File

@ -481,7 +481,12 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
let Ty { id, kind, span, tokens } = ty.deref_mut();
vis.visit_id(id);
match kind {
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {}
TyKind::Infer
| TyKind::ImplicitSelf
| TyKind::Err(_)
| TyKind::Dummy
| TyKind::Never
| TyKind::CVarArgs => {}
TyKind::Slice(ty) => vis.visit_ty(ty),
TyKind::Ptr(mt) => vis.visit_mt(mt),
TyKind::Ref(lt, mt) => {
@ -1649,7 +1654,7 @@ impl DummyAstNode for Ty {
fn dummy() -> Self {
Ty {
id: DUMMY_NODE_ID,
kind: TyKind::Err,
kind: TyKind::Dummy,
span: Default::default(),
tokens: Default::default(),
}

View File

@ -447,7 +447,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
}
TyKind::Typeof(expression) => visitor.visit_anon_const(expression),
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {}
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
TyKind::Never | TyKind::CVarArgs => {}
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {

View File

@ -1286,7 +1286,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
let kind = match &t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => hir::TyKind::Err(self.dcx().has_errors().unwrap()),
TyKind::Err(guar) => hir::TyKind::Err(*guar),
// Lower the anonymous structs or unions in a nested lowering context.
//
// ```
@ -1504,6 +1504,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
hir::TyKind::Err(guar)
}
TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"),
};
hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }

View File

@ -881,7 +881,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
&item.vis,
errors::VisibilityNotPermittedNote::TraitImpl,
);
if let TyKind::Err = self_ty.kind {
// njn: use Dummy here
if let TyKind::Err(_) = self_ty.kind {
this.dcx().emit_err(errors::ObsoleteAuto { span: item.span });
}
if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)

View File

@ -1048,11 +1048,16 @@ impl<'a> State<'a> {
ast::TyKind::Infer => {
self.word("_");
}
ast::TyKind::Err => {
ast::TyKind::Err(_) => {
self.popen();
self.word("/*ERROR*/");
self.pclose();
}
ast::TyKind::Dummy => {
self.popen();
self.word("/*DUMMY*/");
self.pclose();
}
ast::TyKind::ImplicitSelf => {
self.word("Self");
}

View File

@ -567,10 +567,13 @@ impl DummyResult {
}
/// A plain dummy type.
pub fn raw_ty(sp: Span, is_error: bool) -> P<ast::Ty> {
pub fn raw_ty(sp: Span) -> P<ast::Ty> {
// FIXME(nnethercote): you might expect `ast::TyKind::Dummy` to be used here, but some
// values produced here end up being lowered to HIR, which `ast::TyKind::Dummy` does not
// support, so we use an empty tuple instead.
P(ast::Ty {
id: ast::DUMMY_NODE_ID,
kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(ThinVec::new()) },
kind: ast::TyKind::Tup(ThinVec::new()),
span: sp,
tokens: None,
})
@ -611,7 +614,7 @@ impl MacResult for DummyResult {
}
fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> {
Some(DummyResult::raw_ty(self.span, self.is_error))
Some(DummyResult::raw_ty(self.span))
}
fn make_arms(self: Box<DummyResult>) -> Option<SmallVec<[ast::Arm; 1]>> {

View File

@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
CoerceMany::with_coercion_sites(coerce_first, arms)
};
let mut other_arms = vec![]; // Used only for diagnostics.
let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics.
let mut prior_arm = None;
for arm in arms {
if let Some(e) = &arm.guard {
@ -118,9 +118,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prior_arm_ty,
prior_arm_span,
scrut_span: scrut.span,
scrut_hir_id: scrut.hir_id,
source: match_src,
prior_arms: other_arms.clone(),
prior_non_diverging_arms: prior_non_diverging_arms.clone(),
opt_suggest_box_span,
})),
),
@ -142,16 +141,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false,
);
other_arms.push(arm_span);
if other_arms.len() > 5 {
other_arms.remove(0);
}
if !arm_ty.is_never() {
// When a match arm has type `!`, then it doesn't influence the expected type for
// the following arm. If all of the prior arms are `!`, then the influence comes
// from elsewhere and we shouldn't point to any previous arm.
prior_arm = Some((arm_block_id, arm_ty, arm_span));
prior_non_diverging_arms.push(arm_span);
if prior_non_diverging_arms.len() > 5 {
prior_non_diverging_arms.remove(0);
}
}
}

View File

@ -777,10 +777,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
prior_arm_span,
prior_arm_ty,
source,
ref prior_arms,
ref prior_non_diverging_arms,
opt_suggest_box_span,
scrut_span,
scrut_hir_id,
..
}) => match source {
hir::MatchSource::TryDesugar(scrut_hir_id) => {
@ -817,12 +816,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
});
let source_map = self.tcx.sess.source_map();
let mut any_multiline_arm = source_map.is_multiline(arm_span);
if prior_arms.len() <= 4 {
for sp in prior_arms {
if prior_non_diverging_arms.len() <= 4 {
for sp in prior_non_diverging_arms {
any_multiline_arm |= source_map.is_multiline(*sp);
err.span_label(*sp, format!("this is found to be of type `{t}`"));
}
} else if let Some(sp) = prior_arms.last() {
} else if let Some(sp) = prior_non_diverging_arms.last() {
any_multiline_arm |= source_map.is_multiline(*sp);
err.span_label(
*sp,
@ -848,24 +847,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
) {
err.subdiagnostic(subdiag);
}
if let hir::Node::Expr(m) = self.tcx.parent_hir_node(scrut_hir_id)
&& let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(m.hir_id)
&& let hir::StmtKind::Expr(_) = stmt.kind
{
err.span_suggestion_verbose(
stmt.span.shrink_to_hi(),
"consider using a semicolon here, but this will discard any values \
in the match arms",
";",
Applicability::MaybeIncorrect,
);
}
if let Some(ret_sp) = opt_suggest_box_span {
// Get return type span and point to it.
self.suggest_boxing_for_return_impl_trait(
err,
ret_sp,
prior_arms.iter().chain(std::iter::once(&arm_span)).copied(),
prior_non_diverging_arms
.iter()
.chain(std::iter::once(&arm_span))
.copied(),
);
}
}

View File

@ -203,10 +203,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
})
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
prior_arms,
prior_non_diverging_arms,
..
}) => {
if let [.., arm_span] = &prior_arms[..] {
if let [.., arm_span] = &prior_non_diverging_arms[..] {
Some(ConsiderAddingAwait::BothFuturesSugg {
first: arm_span.shrink_to_hi(),
second: exp_span.shrink_to_hi(),
@ -234,11 +234,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
ref prior_arms,
ref prior_non_diverging_arms,
..
}) => Some({
ConsiderAddingAwait::FutureSuggMultiple {
spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(),
spans: prior_non_diverging_arms
.iter()
.map(|arm| arm.shrink_to_hi())
.collect(),
}
}),
_ => None,

View File

@ -569,9 +569,8 @@ pub struct MatchExpressionArmCause<'tcx> {
pub prior_arm_ty: Ty<'tcx>,
pub prior_arm_span: Span,
pub scrut_span: Span,
pub scrut_hir_id: hir::HirId,
pub source: hir::MatchSource,
pub prior_arms: Vec<Span>,
pub prior_non_diverging_arms: Vec<Span>,
pub opt_suggest_box_span: Option<Span>,
}

View File

@ -2363,28 +2363,42 @@ impl<'tcx> Ty<'tcx> {
}
/// When we create a closure, we record its kind (i.e., what trait
/// it implements) into its `ClosureArgs` using a type
/// it implements, constrained by how it uses its borrows) into its
/// [`ty::ClosureArgs`] or [`ty::CoroutineClosureArgs`] using a type
/// parameter. This is kind of a phantom type, except that the
/// most convenient thing for us to are the integral types. This
/// function converts such a special type into the closure
/// kind. To go the other way, use `closure_kind.to_ty(tcx)`.
/// kind. To go the other way, use [`Ty::from_closure_kind`].
///
/// Note that during type checking, we use an inference variable
/// to represent the closure kind, because it has not yet been
/// inferred. Once upvar inference (in `rustc_hir_analysis/src/check/upvar.rs`)
/// is complete, that type variable will be unified.
///
/// To be noted that you can use [`ClosureArgs::kind()`] or [`CoroutineClosureArgs::kind()`]
/// to get the same information, which you can get by calling [`GenericArgs::as_closure()`]
/// or [`GenericArgs::as_coroutine_closure()`], depending on the type of the closure.
///
/// Otherwise, this method can be used as follows:
/// is complete, that type variable will be unified with one of
/// the integral types.
///
/// ```rust,ignore (snippet of compiler code)
/// let TyKind::Closure(def_id, [closure_fn_kind_ty, ..]) = closure_ty.kind()
/// && let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind()
/// if let TyKind::Closure(def_id, args) = closure_ty.kind()
/// && let Some(closure_kind) = args.as_closure().kind_ty().to_opt_closure_kind()
/// {
/// // your code
/// println!("{closure_kind:?}");
/// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind()
/// && let Some(closure_kind) = args.as_coroutine_closure().kind_ty().to_opt_closure_kind()
/// {
/// println!("{closure_kind:?}");
/// }
/// ```
///
/// After upvar analysis, you should instead use [`ClosureArgs::kind()`]
/// or [`CoroutineClosureArgs::kind()`] to assert that the `ClosureKind`
/// has been constrained instead of manually calling this method.
///
/// ```rust,ignore (snippet of compiler code)
/// if let TyKind::Closure(def_id, args) = closure_ty.kind()
/// {
/// println!("{:?}", args.as_closure().kind());
/// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind()
/// {
/// println!("{:?}", args.as_coroutine_closure().kind());
/// }
/// ```
pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> {
@ -2406,7 +2420,8 @@ impl<'tcx> Ty<'tcx> {
}
}
/// Inverse of [`Ty::to_opt_closure_kind`].
/// Inverse of [`Ty::to_opt_closure_kind`]. See docs on that method
/// for explanation of the relationship between `Ty` and [`ty::ClosureKind`].
pub fn from_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> {
match kind {
ty::ClosureKind::Fn => tcx.types.i8,

View File

@ -653,7 +653,6 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
debug!("about to call mir_drops_elaborated...");
let body = tcx.mir_drops_elaborated_and_const_checked(did).steal();
let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst);
debug!("body: {:#?}", body);
if body.tainted_by_errors.is_some() {
return body;

View File

@ -15,7 +15,8 @@ impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
}
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("remove_noop_landing_pads({:?})", body);
let def_id = body.source.def_id();
debug!(?def_id);
self.remove_nop_landing_pads(body)
}
}
@ -81,8 +82,6 @@ impl RemoveNoopLandingPads {
}
fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
debug!("body: {:#?}", body);
// Skip the pass if there are no blocks with a resume terminator.
let has_resume = body
.basic_blocks

View File

@ -46,14 +46,14 @@ use std::ops::{Deref, DerefMut};
use thin_vec::{thin_vec, ThinVec};
/// Creates a placeholder argument.
pub(super) fn dummy_arg(ident: Ident) -> Param {
pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param {
let pat = P(Pat {
id: ast::DUMMY_NODE_ID,
kind: PatKind::Ident(BindingAnnotation::NONE, ident, None),
span: ident.span,
tokens: None,
});
let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None };
let ty = Ty { kind: TyKind::Err(guar), span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None };
Param {
attrs: AttrVec::default(),
id: ast::DUMMY_NODE_ID,
@ -1540,14 +1540,14 @@ impl<'a> Parser<'a> {
pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
if self.token == token::Question {
self.bump();
self.dcx().emit_err(QuestionMarkInType {
let guar = self.dcx().emit_err(QuestionMarkInType {
span: self.prev_token.span,
sugg: QuestionMarkInTypeSugg {
left: ty.span.shrink_to_lo(),
right: self.prev_token.span,
},
});
self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err)
self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err(guar))
} else {
ty
}
@ -2304,8 +2304,8 @@ impl<'a> Parser<'a> {
pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> {
let span = param.pat.span;
param.ty.kind = TyKind::Err;
self.dcx().emit_err(SelfParamNotFirst { span });
let guar = self.dcx().emit_err(SelfParamNotFirst { span });
param.ty.kind = TyKind::Err(guar);
Ok(param)
}
@ -2437,7 +2437,7 @@ impl<'a> Parser<'a> {
pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec<Param>) {
let mut seen_inputs = FxHashSet::default();
for input in fn_inputs.iter_mut() {
let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) =
let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err(_)) =
(&input.pat.kind, &input.ty.kind)
{
Some(*ident)
@ -2644,8 +2644,10 @@ impl<'a> Parser<'a> {
"::",
Applicability::MaybeIncorrect,
);
err.emit();
return Ok(GenericArg::Type(self.mk_ty(start.to(expr.span), TyKind::Err)));
let guar = err.emit();
return Ok(GenericArg::Type(
self.mk_ty(start.to(expr.span), TyKind::Err(guar)),
));
} else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg()
{
// Avoid the following output by checking that we consumed a full const arg:

View File

@ -591,7 +591,23 @@ impl<'a> Parser<'a> {
let ty_second = if self.token == token::DotDot {
// We need to report this error after `cfg` expansion for compatibility reasons
self.bump(); // `..`, do not add it to expected tokens
Some(self.mk_ty(self.prev_token.span, TyKind::Err))
// FIXME(nnethercote): AST validation later detects this
// `TyKind::Err` and emits an errors. So why the unchecked
// ErrorGuaranteed?
// - A `span_delayed_bug` doesn't work here, because rustfmt can
// hit this path but then not hit the follow-up path in the AST
// validator that issues the error, which results in ICEs.
// - `TyKind::Dummy` doesn't work, because it ends up reaching HIR
// lowering, which results in ICEs. Changing `TyKind::Dummy` to
// `TyKind::Err` during AST validation might fix that, but that's
// not possible because AST validation doesn't allow mutability.
//
// #121072 will hopefully remove all this special handling of the
// obsolete `impl Trait for ..` and then this can go away.
#[allow(deprecated)]
let guar = rustc_errors::ErrorGuaranteed::unchecked_error_guaranteed();
Some(self.mk_ty(self.prev_token.span, TyKind::Err(guar)))
} else if has_for || self.token.can_begin_type() {
Some(self.parse_ty()?)
} else {
@ -2628,13 +2644,13 @@ impl<'a> Parser<'a> {
p.recover_diff_marker();
let snapshot = p.create_snapshot_for_diagnostic();
let param = p.parse_param_general(req_name, first_param).or_else(|e| {
e.emit();
let guar = e.emit();
let lo = p.prev_token.span;
p.restore_snapshot(snapshot);
// Skip every token until next possible arg or end.
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(Delimiter::Parenthesis)]);
// Create a placeholder argument for proper arg count (issue #34264).
Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span))))
Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)), guar))
});
// ...now that we've parsed the first argument, `self` is no longer allowed.
first_param = false;
@ -2671,8 +2687,8 @@ impl<'a> Parser<'a> {
return if let Some(ident) =
this.parameter_without_type(&mut err, pat, is_name_required, first_param)
{
err.emit();
Ok((dummy_arg(ident), TrailingToken::None))
let guar = err.emit();
Ok((dummy_arg(ident, guar), TrailingToken::None))
} else {
Err(err)
};

View File

@ -678,8 +678,9 @@ impl<'a> Parser<'a> {
c.into()
}
Some(GenericArg::Lifetime(lt)) => {
self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
self.mk_ty(span, ast::TyKind::Err).into()
let guar =
self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
self.mk_ty(span, ast::TyKind::Err(guar)).into()
}
None => {
let after_eq = eq.shrink_to_hi();
@ -779,7 +780,7 @@ impl<'a> Parser<'a> {
// type to determine if error recovery has occurred and if the input is not a
// syntactically valid type after all.
if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind
&& let ast::TyKind::Err = inner_ty.kind
&& let ast::TyKind::Err(_) = inner_ty.kind
&& let Some(snapshot) = snapshot
&& let Some(expr) =
self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)

View File

@ -346,8 +346,10 @@ impl<'a> Parser<'a> {
AllowCVariadic::No => {
// FIXME(Centril): Should we just allow `...` syntactically
// anywhere in a type and use semantic restrictions instead?
self.dcx().emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) });
TyKind::Err
let guar = self
.dcx()
.emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) });
TyKind::Err(guar)
}
}
} else {
@ -493,8 +495,8 @@ impl<'a> Parser<'a> {
{
// Recover from `[LIT; EXPR]` and `[LIT]`
self.bump();
err.emit();
self.mk_ty(self.prev_token.span, TyKind::Err)
let guar = err.emit();
self.mk_ty(self.prev_token.span, TyKind::Err(guar))
}
Err(err) => return Err(err),
};

View File

@ -616,8 +616,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
Infer,
ImplicitSelf,
MacCall,
Err,
CVarArgs
CVarArgs,
Dummy,
Err
]
);

View File

@ -86,7 +86,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
// tidy-alphabetical-start
// FEAT_AES
// FEAT_AES & FEAT_PMULL
("aes", Stable),
// FEAT_BF16
("bf16", Stable),
@ -124,7 +124,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
("lor", Stable),
// FEAT_LSE
("lse", Stable),
// FEAT_MTE
// FEAT_MTE & FEAT_MTE2
("mte", Stable),
// FEAT_AdvSimd & FEAT_FP
("neon", Stable),
@ -138,7 +138,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
("pmuv3", Stable),
// FEAT_RAND
("rand", Stable),
// FEAT_RAS
// FEAT_RAS & FEAT_RASv1p1
("ras", Stable),
// FEAT_RCPC
("rcpc", Stable),
@ -156,7 +156,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
("sm4", Stable),
// FEAT_SPE
("spe", Stable),
// FEAT_SSBS
// FEAT_SSBS & FEAT_SSBS2
("ssbs", Stable),
// FEAT_SVE
("sve", Stable),

View File

@ -8,14 +8,16 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur
*[other] arguments
}
trait_selection_closure_fn_mut_label = closure is `FnMut` because it mutates the variable `{$place}` here
trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment
trait_selection_closure_fn_once_label = closure is `FnOnce` because it moves the variable `{$place}` out of its environment
trait_selection_closure_fn_mut_label = closure is `{$trait_prefix}FnMut` because it mutates the variable `{$place}` here
trait_selection_closure_kind_mismatch = expected a closure that implements the `{$expected}` trait, but this closure only implements `{$found}`
.label = this closure implements `{$found}`, not `{$expected}`
trait_selection_closure_fn_once_label = closure is `{$trait_prefix}FnOnce` because it moves the variable `{$place}` out of its environment
trait_selection_closure_kind_requirement = the requirement to implement `{$expected}` derives from here
trait_selection_closure_kind_mismatch = expected a closure that implements the `{$trait_prefix}{$expected}` trait, but this closure only implements `{$trait_prefix}{$found}`
.label = this closure implements `{$trait_prefix}{$found}`, not `{$trait_prefix}{$expected}`
trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here
trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}

View File

@ -135,6 +135,8 @@ pub struct ClosureKindMismatch {
#[label(trait_selection_closure_kind_requirement)]
pub cause_span: Span,
pub trait_prefix: &'static str,
#[subdiagnostic]
pub fn_once_label: Option<ClosureFnOnceLabel>,
@ -157,3 +159,11 @@ pub struct ClosureFnMutLabel {
pub span: Span,
pub place: String,
}
#[derive(Diagnostic)]
#[diag(trait_selection_async_closure_not_fn)]
pub(crate) struct AsyncClosureNotFn {
#[primary_span]
pub span: Span,
pub kind: &'static str,
}

View File

@ -2,7 +2,9 @@
use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _};
use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch};
use crate::errors::{
AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
};
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::InferCtxtExt as _;
@ -959,34 +961,102 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn emit_specialized_closure_kind_error(
&self,
obligation: &PredicateObligation<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
mut trait_ref: ty::PolyTraitRef<'tcx>,
) -> Option<ErrorGuaranteed> {
let self_ty = trait_ref.self_ty().skip_binder();
if let ty::Closure(closure_def_id, closure_args) = *self_ty.kind()
&& let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
&& let Some(found_kind) = self.closure_kind(self_ty)
// If `AsyncFnKindHelper` is not implemented, that means that the closure kind
// doesn't extend the goal kind. This is worth reporting, but we can only do so
// if we actually know which closure this goal comes from, so look at the cause
// to see if we can extract that information.
if Some(trait_ref.def_id()) == self.tcx.lang_items().async_fn_kind_helper()
&& let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind()
&& let Some(expected_kind) =
trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
&& !found_kind.extends(expected_kind)
&& let sig = closure_args.as_closure().sig()
&& self.can_sub(
obligation.param_env,
trait_ref,
sig.map_bound(|sig| {
ty::TraitRef::new(
self.tcx,
trait_ref.def_id(),
[trait_ref.self_ty().skip_binder(), sig.inputs()[0]],
)
}),
)
{
let mut err =
self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
Some(err.emit())
} else {
None
if let Some((_, Some(parent))) = obligation.cause.code().parent() {
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
trait_ref = parent.to_poly_trait_ref();
} else if let &ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
obligation.cause.code()
&& let Some(typeck_results) = &self.typeck_results
&& let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
*typeck_results.node_type(arg_hir_id).kind()
{
// Otherwise, extract the closure kind from the obligation.
let mut err = self.report_closure_error(
&obligation,
closure_def_id,
found_kind,
expected_kind,
"async ",
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
return Some(err.emit());
}
}
let self_ty = trait_ref.self_ty().skip_binder();
if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) {
let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
ty::Closure(def_id, args) => {
(def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
}
ty::CoroutineClosure(def_id, args) => (
def_id,
args.as_coroutine_closure()
.coroutine_closure_sig()
.map_bound(|sig| sig.tupled_inputs_ty),
Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
),
_ => return None,
};
let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1));
// Verify that the arguments are compatible. If the signature is
// mismatched, then we have a totally different error to report.
if self.enter_forall(found_args, |found_args| {
self.enter_forall(expected_args, |expected_args| {
!self.can_sub(obligation.param_env, expected_args, found_args)
})
}) {
return None;
}
if let Some(found_kind) = self.closure_kind(self_ty)
&& !found_kind.extends(expected_kind)
{
let mut err = self.report_closure_error(
&obligation,
closure_def_id,
found_kind,
expected_kind,
"",
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
return Some(err.emit());
}
// If the closure has captures, then perhaps the reason that the trait
// is unimplemented is because async closures don't implement `Fn`/`FnMut`
// if they have captures.
if let Some(by_ref_captures) = by_ref_captures
&& let ty::FnPtr(sig) = by_ref_captures.kind()
&& !sig.skip_binder().output().is_unit()
{
let mut err = self.tcx.dcx().create_err(AsyncClosureNotFn {
span: self.tcx.def_span(closure_def_id),
kind: expected_kind.as_str(),
});
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
return Some(err.emit());
}
}
None
}
fn fn_arg_obligation(
@ -1493,6 +1563,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> {
closure_def_id: DefId,
found_kind: ty::ClosureKind,
kind: ty::ClosureKind,
trait_prefix: &'static str,
) -> DiagnosticBuilder<'tcx>;
fn report_cyclic_signature_error(
@ -3376,6 +3447,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
closure_def_id: DefId,
found_kind: ty::ClosureKind,
kind: ty::ClosureKind,
trait_prefix: &'static str,
) -> DiagnosticBuilder<'tcx> {
let closure_span = self.tcx.def_span(closure_def_id);
@ -3384,6 +3456,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
expected: kind,
found: found_kind,
cause_span: obligation.cause.span,
trait_prefix,
fn_once_label: None,
fn_mut_label: None,
};

View File

@ -472,6 +472,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")]
@ -552,6 +554,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_unsigned(2), 3);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")]
@ -606,6 +610,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).strict_sub(1), ", stringify!($SelfT), "::MIN + 1);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")]
@ -686,6 +692,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub_unsigned(2), -1);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")]
@ -740,6 +748,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.strict_mul(1), ", stringify!($SelfT), "::MAX);")]
/// ```
///
/// The following panics because of overflow:
///
/// ``` should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")]
@ -831,11 +841,15 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div(-1), ", stringify!($Max), ");")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div(-1);")]
/// ```
///
/// The following panics because of division by zero:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")]
@ -901,11 +915,15 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div_euclid(-1), ", stringify!($Max), ");")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div_euclid(-1);")]
/// ```
///
/// The following panics because of division by zero:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")]
@ -970,11 +988,15 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem(2), 1);")]
/// ```
///
/// The following panics because of division by zero:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")]
@ -1039,11 +1061,15 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem_euclid(2), 1);")]
/// ```
///
/// The following panics because of division by zero:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")]
@ -1121,6 +1147,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_neg(), -5);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")]
@ -1175,6 +1203,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")]
@ -1256,6 +1286,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")]
@ -1340,6 +1372,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").strict_abs(), 5);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")]
@ -1414,6 +1448,8 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(8", stringify!($SelfT), ".strict_pow(2), 64);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")]

View File

@ -480,6 +480,8 @@ macro_rules! uint_impl {
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")]
@ -561,6 +563,8 @@ macro_rules! uint_impl {
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_signed(2), 3);")]
/// ```
///
/// The following panic because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_add_signed(-2);")]
@ -620,6 +624,8 @@ macro_rules! uint_impl {
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub(1), 0);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")]
@ -700,6 +706,8 @@ macro_rules! uint_impl {
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_mul(1), 5);")]
/// ```
///
/// The following panics because of overflow:
///
/// ``` should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")]
@ -785,6 +793,13 @@ macro_rules! uint_impl {
/// #![feature(strict_overflow_ops)]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div(10), 10);")]
/// ```
///
/// The following panics because of division by zero:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
@ -840,6 +855,12 @@ macro_rules! uint_impl {
/// #![feature(strict_overflow_ops)]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div_euclid(10), 10);")]
/// ```
/// The following panics because of division by zero:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
@ -895,6 +916,13 @@ macro_rules! uint_impl {
/// #![feature(strict_overflow_ops)]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem(10), 0);")]
/// ```
///
/// The following panics because of division by zero:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
@ -951,6 +979,13 @@ macro_rules! uint_impl {
/// #![feature(strict_overflow_ops)]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem_euclid(10), 0);")]
/// ```
///
/// The following panics because of division by zero:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")]
/// ```
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
#[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
#[must_use = "this returns the result of the operation, \
@ -1172,6 +1207,8 @@ macro_rules! uint_impl {
#[doc = concat!("assert_eq!(0", stringify!($SelfT), ".strict_neg(), 0);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")]
@ -1226,6 +1263,8 @@ macro_rules! uint_impl {
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")]
@ -1307,6 +1346,8 @@ macro_rules! uint_impl {
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")]
@ -1406,6 +1447,8 @@ macro_rules! uint_impl {
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".strict_pow(5), 32);")]
/// ```
///
/// The following panics because of overflow:
///
/// ```should_panic
/// #![feature(strict_overflow_ops)]
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")]

View File

@ -161,7 +161,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
// first E0 A0 80 last EF BF BF
// excluding surrogates codepoints \u{d800} to \u{dfff}
// ED A0 80 to ED BF BF
// 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff
// 4-byte encoding is for codepoints \u{10000} to \u{10ffff}
// first F0 90 80 80 last F4 8F BF BF
//
// Use the UTF-8 syntax from the RFC

View File

@ -99,21 +99,21 @@ fn skip_search<const SOR: usize, const OFFSETS: usize>(
offset_idx % 2 == 1
}
pub const UNICODE_VERSION: (u8, u8, u8) = (15, 0, 0);
pub const UNICODE_VERSION: (u8, u8, u8) = (15, 1, 0);
#[rustfmt::skip]
pub mod alphabetic {
static SHORT_OFFSET_RUNS: [u32; 53] = [
static SHORT_OFFSET_RUNS: [u32; 54] = [
706, 33559113, 872420973, 952114966, 1161831606, 1310731264, 1314926597, 1394619392,
1444957632, 1447077005, 1451271693, 1459672996, 1648425216, 1658911342, 1661009214,
1707147904, 1793132343, 1887506048, 2040601600, 2392923872, 2481005466, 2504077200,
2514564144, 2520859648, 2527151687, 2529257472, 2531355193, 2533453376, 2564917240,
2596375766, 2600579056, 2606870819, 2621551356, 2642525184, 2644628480, 2665600678,
2743197440, 2791432848, 2841765072, 2850154464, 2854350336, 2887905584, 3026321408,
3038947040, 3041048378, 3045248674, 3053644769, 3057842176, 3059939870, 3062038528,
3064140619, 3066241968, 3071550384,
3038947040, 3041048378, 3045248674, 3053644769, 3057839710, 3062036480, 3064134174,
3066232832, 3068334923, 3070436272, 3075744688,
];
static OFFSETS: [u8; 1465] = [
static OFFSETS: [u8; 1467] = [
65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 42,
5, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, 39,
14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, 10,
@ -167,7 +167,7 @@ pub mod alphabetic {
1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1,
1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2,
4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32,
0, 6, 222, 2, 0, 14, 0, 0, 0, 0, 0, 5, 0, 0,
0, 6, 222, 2, 0, 14, 0, 15, 0, 0, 0, 0, 0, 5, 0, 0,
];
pub fn lookup(c: char) -> bool {
super::skip_search(

View File

@ -40,6 +40,9 @@ use crate::lint::init_lints;
pub(crate) struct GlobalTestOptions {
/// Whether to disable the default `extern crate my_crate;` when creating doctests.
pub(crate) no_crate_inject: bool,
/// Whether inserting extra indent spaces in code block,
/// default is `false`, only `true` for generating code link of Rust playground
pub(crate) insert_indent_space: bool,
/// Additional crate-level attributes to add to doctests.
pub(crate) attrs: Vec<String>,
}
@ -221,7 +224,8 @@ pub(crate) fn run_tests(
fn scrape_test_config(attrs: &[ast::Attribute]) -> GlobalTestOptions {
use rustc_ast_pretty::pprust;
let mut opts = GlobalTestOptions { no_crate_inject: false, attrs: Vec::new() };
let mut opts =
GlobalTestOptions { no_crate_inject: false, attrs: Vec::new(), insert_indent_space: false };
let test_attrs: Vec<_> = attrs
.iter()
@ -725,7 +729,17 @@ pub(crate) fn make_test(
// /// ``` <- end of the inner main
line_offset += 1;
prog.extend([&main_pre, everything_else, &main_post].iter().cloned());
// add extra 4 spaces for each line to offset the code block
let content = if opts.insert_indent_space {
everything_else
.lines()
.map(|line| format!(" {}", line))
.collect::<Vec<String>>()
.join("\n")
} else {
everything_else.to_string()
};
prog.extend([&main_pre, content.as_str(), &main_post].iter().cloned());
}
debug!("final doctest:\n{prog}");

View File

@ -53,7 +53,8 @@ assert_eq!(2+2, 4);
fn make_test_no_crate_inject() {
// Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip
// adding it anyway.
let opts = GlobalTestOptions { no_crate_inject: true, attrs: vec![] };
let opts =
GlobalTestOptions { no_crate_inject: true, attrs: vec![], insert_indent_space: false };
let input = "use asdf::qwop;
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
@ -302,3 +303,44 @@ assert_eq!(2+2, 4);
make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name"));
assert_eq!((output, len), (expected, 2));
}
#[test]
fn make_test_insert_extra_space() {
// will insert indent spaces in the code block if `insert_indent_space` is true
let opts =
GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true };
let input = "use std::*;
assert_eq!(2+2, 4);
eprintln!(\"hello anan\");
";
let expected = "#![allow(unused)]
fn main() {
use std::*;
assert_eq!(2+2, 4);
eprintln!(\"hello anan\");
}"
.to_string();
let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 2));
}
#[test]
fn make_test_insert_extra_space_fn_main() {
// if input already has a fn main, it should insert a space before it
let opts =
GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true };
let input = "use std::*;
fn main() {
assert_eq!(2+2, 4);
eprintln!(\"hello anan\");
}";
let expected = "#![allow(unused)]
use std::*;
fn main() {
assert_eq!(2+2, 4);
eprintln!(\"hello anan\");
}"
.to_string();
let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
assert_eq!((output, len), (expected, 1));
}

View File

@ -45,6 +45,7 @@ use std::str::{self, CharIndices};
use crate::clean::RenderedLink;
use crate::doctest;
use crate::doctest::GlobalTestOptions;
use crate::html::escape::Escape;
use crate::html::format::Buffer;
use crate::html::highlight;
@ -302,8 +303,10 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
.intersperse("\n".into())
.collect::<String>();
let krate = krate.as_ref().map(|s| s.as_str());
let (test, _, _) =
doctest::make_test(&test, krate, false, &Default::default(), edition, None);
let mut opts: GlobalTestOptions = Default::default();
opts.insert_indent_space = true;
let (test, _, _) = doctest::make_test(&test, krate, false, &opts, edition, None);
let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
let test_escaped = small_url_encode(test);

View File

@ -690,7 +690,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
match (&l.kind, &r.kind) {
(Paren(l), _) => eq_ty(l, r),
(_, Paren(r)) => eq_ty(l, r),
(Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err, Err) | (CVarArgs, CVarArgs) => true,
(Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err(_), Err(_)) | (CVarArgs, CVarArgs) => true,
(Slice(l), Slice(r)) => eq_ty(l, r),
(Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value),
(Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty),

View File

@ -859,7 +859,7 @@ impl Rewrite for ast::Ty {
})
}
ast::TyKind::CVarArgs => Some("...".to_owned()),
ast::TyKind::Err => Some(context.snippet(self.span).to_owned()),
ast::TyKind::Dummy | ast::TyKind::Err(_) => Some(context.snippet(self.span).to_owned()),
ast::TyKind::Typeof(ref anon_const) => rewrite_call(
context,
"typeof",

View File

@ -10,4 +10,4 @@
pub fn dummy() {}
// ensure that `extern crate foo;` was inserted into code snips automatically:
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0Ause+foo::dummy;%0Adummy();%0A%7D&edition=2015"]' "Run"
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0A++++use+foo::dummy;%0A++++dummy();%0A%7D&edition=2015"]' "Run"

View File

@ -22,6 +22,6 @@
//! }
//! ```
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0Aprintln!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "Run"

View File

@ -0,0 +1,15 @@
// edition:2021
// FIXME(async_closures): This needs a better error message!
#![feature(async_closure)]
fn main() {
fn needs_fn<T>(_: impl FnMut() -> T) {}
let mut x = 1;
needs_fn(async || {
//~^ ERROR async closure does not implement `FnMut` because it captures state from its environment
x += 1;
});
}

View File

@ -0,0 +1,16 @@
error: async closure does not implement `FnMut` because it captures state from its environment
--> $DIR/not-fn.rs:11:14
|
LL | needs_fn(async || {
| -------- ^^^^^^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `needs_fn`
--> $DIR/not-fn.rs:8:28
|
LL | fn needs_fn<T>(_: impl FnMut() -> T) {}
| ^^^^^^^^^^^^ required by this bound in `needs_fn`
error: aborting due to 1 previous error

View File

@ -9,8 +9,7 @@ fn main() {
let mut x = 1;
needs_async_fn(async || {
//~^ ERROR i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>
// FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth.
//~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
x += 1;
});
}

View File

@ -1,15 +1,17 @@
error[E0277]: the trait bound `i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>` is not satisfied
error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
--> $DIR/wrong-fn-kind.rs:11:20
|
LL | needs_async_fn(async || {
| _____--------------_^
| -------------- -^^^^^^^
| | |
| _____|______________this closure implements `async FnMut`, not `async Fn`
| | |
| | required by a bound introduced by this call
LL | |
LL | | // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth.
LL | | x += 1;
| | - closure is `async FnMut` because it mutates the variable `x` here
LL | | });
| |_____^ the trait `ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>` is not implemented for `i16`
| |_____- the requirement to implement `async Fn` derives from here
|
note: required by a bound in `needs_async_fn`
--> $DIR/wrong-fn-kind.rs:8:31
@ -19,4 +21,4 @@ LL | fn needs_async_fn(_: impl async Fn()) {}
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0525`.

View File

@ -0,0 +1,17 @@
fn main() {
let m = 42u32;
let value = 'out: {
match m {
1 => break 'out Some(1u16),
2 => Some(2u16),
3 => break 'out Some(3u16),
4 => break 'out Some(4u16),
5 => break 'out Some(5u16),
_ => {}
//~^ ERROR `match` arms have incompatible types
}
None
};
}

View File

@ -0,0 +1,21 @@
error[E0308]: `match` arms have incompatible types
--> $DIR/dont-highlight-diverging-arms.rs:11:18
|
LL | / match m {
LL | | 1 => break 'out Some(1u16),
LL | | 2 => Some(2u16),
| | ---------- this is found to be of type `Option<u16>`
LL | | 3 => break 'out Some(3u16),
... |
LL | | _ => {}
| | ^^ expected `Option<u16>`, found `()`
LL | |
LL | | }
| |_________- `match` arms have incompatible types
|
= note: expected enum `Option<u16>`
found unit type `()`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -3,11 +3,14 @@ error[E0308]: `match` arms have incompatible types
|
LL | / match E::F {
LL | | E::A => 1,
| | - this is found to be of type `{integer}`
LL | | E::B => 2,
| | - this is found to be of type `{integer}`
LL | | E::C => 3,
| | - this is found to be of type `{integer}`
LL | | E::D => 4,
| | - this is found to be of type `{integer}`
LL | | E::E => unimplemented!(""),
| | ------------------ this and all prior arms are found to be of type `{integer}`
LL | | E::F => "",
| | ^^ expected integer, found `&str`
LL | | };

View File

@ -4,22 +4,15 @@ error[E0308]: `match` arms have incompatible types
LL | / match num {
LL | | 1 => {
LL | | cx.answer_str("hi");
| | -------------------- this is found to be of type `()`
| | --------------------
| | | |
| | | help: consider removing this semicolon
| | this is found to be of type `()`
LL | | }
LL | | _ => cx.answer_str("hi"),
| | ^^^^^^^^^^^^^^^^^^^ expected `()`, found future
LL | | }
| |_____- `match` arms have incompatible types
|
help: consider removing this semicolon
|
LL - cx.answer_str("hi");
LL + cx.answer_str("hi")
|
help: consider using a semicolon here, but this will discard any values in the match arms
|
LL | };
| +
error: aborting due to 1 previous error

View File

@ -11,10 +11,6 @@ LL | | }
|
= note: expected reference `&S`
found reference `&R`
help: consider using a semicolon here, but this will discard any values in the match arms
|
LL | };
| +
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/wf-unsafe-trait-obj-match.rs:26:21