mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 05:51:58 +00:00
Auto merge of #120089 - matthiaskrgr:rollup-xyfqrb5, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #119172 (Detect `NulInCStr` error earlier.) - #119833 (Make tcx optional from StableMIR run macro and extend it to accept closures) - #119967 (Add `PatKind::Err` to AST/HIR) - #119978 (Move async closure parameters into the resultant closure's future eagerly) - #120021 (don't store const var origins for known vars) - #120038 (Don't create a separate "basename" when naming and opening a MIR dump file) - #120057 (Don't ICE when deducing future output if other errors already occurred) - #120073 (Remove spastorino from users_on_vacation) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8424f8e8cd
@ -625,7 +625,8 @@ impl Pat {
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Ident(..)
|
||||
| PatKind::Path(..)
|
||||
| PatKind::MacCall(_) => {}
|
||||
| PatKind::MacCall(_)
|
||||
| PatKind::Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -809,6 +810,9 @@ pub enum PatKind {
|
||||
|
||||
/// A macro pattern; pre-expansion.
|
||||
MacCall(P<MacCall>),
|
||||
|
||||
/// Placeholder for a pattern that wasn't syntactically well formed in some way.
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
/// Whether the `..` is present in a struct fields pattern.
|
||||
|
@ -1267,7 +1267,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
||||
let Pat { id, kind, span, tokens } = pat.deref_mut();
|
||||
vis.visit_id(id);
|
||||
match kind {
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {}
|
||||
PatKind::Ident(_binding_mode, ident, sub) => {
|
||||
vis.visit_ident(ident);
|
||||
visit_opt(sub, |sub| vis.visit_pat(sub));
|
||||
|
@ -8,7 +8,6 @@ use rustc_lexer::unescape::{
|
||||
};
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use std::ops::Range;
|
||||
use std::{ascii, fmt, str};
|
||||
|
||||
// Escapes a string, represented as a symbol. Reuses the original symbol,
|
||||
@ -39,7 +38,6 @@ pub enum LitError {
|
||||
InvalidFloatSuffix,
|
||||
NonDecimalFloat(u32),
|
||||
IntTooLarge(u32),
|
||||
NulInCStr(Range<usize>),
|
||||
}
|
||||
|
||||
impl LitKind {
|
||||
@ -156,10 +154,7 @@ impl LitKind {
|
||||
let s = symbol.as_str();
|
||||
let mut buf = Vec::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
|
||||
Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
|
||||
error = Err(LitError::NulInCStr(span));
|
||||
}
|
||||
unescape_c_string(s, Mode::CStr, &mut |_span, c| match c {
|
||||
Ok(CStrUnit::Byte(b)) => buf.push(b),
|
||||
Ok(CStrUnit::Char(c)) => {
|
||||
buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
|
||||
@ -179,10 +174,7 @@ impl LitKind {
|
||||
// can convert the symbol directly to a `Lrc<u8>` on success.
|
||||
let s = symbol.as_str();
|
||||
let mut error = Ok(());
|
||||
unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
|
||||
Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
|
||||
error = Err(LitError::NulInCStr(span));
|
||||
}
|
||||
unescape_c_string(s, Mode::RawCStr, &mut |_, c| match c {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
if err.is_fatal() {
|
||||
|
@ -568,7 +568,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
||||
walk_list!(visitor, visit_expr, lower_bound);
|
||||
walk_list!(visitor, visit_expr, upper_bound);
|
||||
}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {}
|
||||
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
}
|
||||
|
@ -14,10 +14,6 @@ ast_lowering_assoc_ty_parentheses =
|
||||
ast_lowering_async_coroutines_not_supported =
|
||||
`async` coroutines are not yet supported
|
||||
|
||||
ast_lowering_async_non_move_closure_not_supported =
|
||||
`async` non-`move` closures with parameters are not currently supported
|
||||
.help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure
|
||||
|
||||
ast_lowering_att_syntax_only_x86 =
|
||||
the `att_syntax` option is only supported on x86
|
||||
|
||||
|
@ -145,14 +145,6 @@ pub struct ClosureCannotBeStatic {
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[help]
|
||||
#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")]
|
||||
pub struct AsyncNonMoveClosureNotSupported {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
||||
pub struct FunctionalRecordUpdateDestructuringAssignment {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::errors::{
|
||||
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
||||
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
|
||||
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
|
||||
ClosureCannotBeStatic, CoroutineTooManyParameters,
|
||||
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
|
||||
NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
|
||||
UnderscoreExprLhsAssign,
|
||||
@ -13,7 +13,6 @@ use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
@ -1028,28 +1027,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn_decl_span: Span,
|
||||
fn_arg_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let CoroutineKind::Async { closure_id: inner_closure_id, .. } = coroutine_kind else {
|
||||
span_bug!(fn_decl_span, "`async gen` and `gen` closures are not supported, yet");
|
||||
};
|
||||
|
||||
if let &ClosureBinder::For { span, .. } = binder {
|
||||
self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
|
||||
}
|
||||
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let outer_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
let body = self.with_new_scopes(fn_decl_span, |this| {
|
||||
// FIXME(cramertj): allow `async` non-`move` closures with arguments.
|
||||
if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
|
||||
this.dcx().emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span });
|
||||
}
|
||||
|
||||
// Transform `async |x: u8| -> X { ... }` into
|
||||
// `|x: u8| || -> X { ... }`.
|
||||
let body_id = this.lower_fn_body(&outer_decl, |this| {
|
||||
let body_id = this.lower_body(|this| {
|
||||
let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
|
||||
let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
|
||||
Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx)))
|
||||
@ -1057,22 +1044,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
None
|
||||
};
|
||||
|
||||
let async_body = this.make_desugared_coroutine_expr(
|
||||
capture_clause,
|
||||
inner_closure_id,
|
||||
async_ret_ty,
|
||||
body.span,
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Closure,
|
||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||
decl,
|
||||
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
||||
body.span,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Closure,
|
||||
async_ret_ty,
|
||||
);
|
||||
let hir_id = this.lower_node_id(inner_closure_id);
|
||||
|
||||
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
|
||||
hir::Expr { hir_id, kind: async_body, span: this.lower_span(body.span) }
|
||||
|
||||
(parameters, expr)
|
||||
});
|
||||
body_id
|
||||
});
|
||||
|
||||
let outer_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
// We need to lower the declaration outside the new scope, because we
|
||||
// have to conserve the state of being inside a loop condition for the
|
||||
|
@ -1082,196 +1082,226 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else {
|
||||
return self.lower_fn_body_block(span, decl, body);
|
||||
};
|
||||
let closure_id = coroutine_kind.closure_id();
|
||||
|
||||
self.lower_body(|this| {
|
||||
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
||||
let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
|
||||
|
||||
// Async function parameters are lowered into the closure body so that they are
|
||||
// captured and so that the drop order matches the equivalent non-async functions.
|
||||
//
|
||||
// from:
|
||||
//
|
||||
// async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
|
||||
// <body>
|
||||
// }
|
||||
//
|
||||
// into:
|
||||
//
|
||||
// fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
|
||||
// async move {
|
||||
// let __arg2 = __arg2;
|
||||
// let <pattern> = __arg2;
|
||||
// let __arg1 = __arg1;
|
||||
// let <pattern> = __arg1;
|
||||
// let __arg0 = __arg0;
|
||||
// let <pattern> = __arg0;
|
||||
// drop-temps { <body> } // see comments later in fn for details
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// If `<pattern>` is a simple ident, then it is lowered to a single
|
||||
// `let <pattern> = <pattern>;` statement as an optimization.
|
||||
//
|
||||
// Note that the body is embedded in `drop-temps`; an
|
||||
// equivalent desugaring would be `return { <body>
|
||||
// };`. The key point is that we wish to drop all the
|
||||
// let-bound variables and temporaries created in the body
|
||||
// (and its tail expression!) before we drop the
|
||||
// parameters (c.f. rust-lang/rust#64512).
|
||||
for (index, parameter) in decl.inputs.iter().enumerate() {
|
||||
let parameter = this.lower_param(parameter);
|
||||
let span = parameter.pat.span;
|
||||
|
||||
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
|
||||
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
|
||||
let (ident, is_simple_parameter) = match parameter.pat.kind {
|
||||
hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
|
||||
(ident, true)
|
||||
}
|
||||
// For `ref mut` or wildcard arguments, we can't reuse the binding, but
|
||||
// we can keep the same name for the parameter.
|
||||
// This lets rustdoc render it correctly in documentation.
|
||||
hir::PatKind::Binding(_, _, ident, _) => (ident, false),
|
||||
hir::PatKind::Wild => {
|
||||
(Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
|
||||
}
|
||||
_ => {
|
||||
// Replace the ident for bindings that aren't simple.
|
||||
let name = format!("__arg{index}");
|
||||
let ident = Ident::from_str(&name);
|
||||
|
||||
(ident, false)
|
||||
}
|
||||
};
|
||||
|
||||
let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None);
|
||||
|
||||
// Construct a parameter representing `__argN: <ty>` to replace the parameter of the
|
||||
// async function.
|
||||
//
|
||||
// If this is the simple case, this parameter will end up being the same as the
|
||||
// original parameter, but with a different pattern id.
|
||||
let stmt_attrs = this.attrs.get(¶meter.hir_id.local_id).copied();
|
||||
let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
|
||||
let new_parameter = hir::Param {
|
||||
hir_id: parameter.hir_id,
|
||||
pat: new_parameter_pat,
|
||||
ty_span: this.lower_span(parameter.ty_span),
|
||||
span: this.lower_span(parameter.span),
|
||||
};
|
||||
|
||||
if is_simple_parameter {
|
||||
// If this is the simple case, then we only insert one statement that is
|
||||
// `let <pat> = <pat>;`. We re-use the original argument's pattern so that
|
||||
// `HirId`s are densely assigned.
|
||||
let expr = this.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let stmt = this.stmt_let_pat(
|
||||
stmt_attrs,
|
||||
desugared_span,
|
||||
Some(expr),
|
||||
parameter.pat,
|
||||
hir::LocalSource::AsyncFn,
|
||||
);
|
||||
statements.push(stmt);
|
||||
} else {
|
||||
// If this is not the simple case, then we construct two statements:
|
||||
//
|
||||
// ```
|
||||
// let __argN = __argN;
|
||||
// let <pat> = __argN;
|
||||
// ```
|
||||
//
|
||||
// The first statement moves the parameter into the closure and thus ensures
|
||||
// that the drop order is correct.
|
||||
//
|
||||
// The second statement creates the bindings that the user wrote.
|
||||
|
||||
// Construct the `let mut __argN = __argN;` statement. It must be a mut binding
|
||||
// because the user may have specified a `ref mut` binding in the next
|
||||
// statement.
|
||||
let (move_pat, move_id) = this.pat_ident_binding_mode(
|
||||
desugared_span,
|
||||
ident,
|
||||
hir::BindingAnnotation::MUT,
|
||||
);
|
||||
let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let move_stmt = this.stmt_let_pat(
|
||||
None,
|
||||
desugared_span,
|
||||
Some(move_expr),
|
||||
move_pat,
|
||||
hir::LocalSource::AsyncFn,
|
||||
);
|
||||
|
||||
// Construct the `let <pat> = __argN;` statement. We re-use the original
|
||||
// parameter's pattern so that `HirId`s are densely assigned.
|
||||
let pattern_expr = this.expr_ident(desugared_span, ident, move_id);
|
||||
let pattern_stmt = this.stmt_let_pat(
|
||||
stmt_attrs,
|
||||
desugared_span,
|
||||
Some(pattern_expr),
|
||||
parameter.pat,
|
||||
hir::LocalSource::AsyncFn,
|
||||
);
|
||||
|
||||
statements.push(move_stmt);
|
||||
statements.push(pattern_stmt);
|
||||
};
|
||||
|
||||
parameters.push(new_parameter);
|
||||
}
|
||||
|
||||
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
|
||||
// Create a block from the user's function body:
|
||||
let user_body = this.lower_block_expr(body);
|
||||
|
||||
// Transform into `drop-temps { <user-body> }`, an expression:
|
||||
let desugared_span =
|
||||
this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
|
||||
let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body));
|
||||
|
||||
// As noted above, create the final block like
|
||||
//
|
||||
// ```
|
||||
// {
|
||||
// let $param_pattern = $raw_param;
|
||||
// ...
|
||||
// drop-temps { <user-body> }
|
||||
// }
|
||||
// ```
|
||||
let body = this.block_all(
|
||||
desugared_span,
|
||||
this.arena.alloc_from_iter(statements),
|
||||
Some(user_body),
|
||||
);
|
||||
|
||||
this.expr_block(body)
|
||||
};
|
||||
let desugaring_kind = match coroutine_kind {
|
||||
CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
|
||||
CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
|
||||
CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
|
||||
};
|
||||
let coroutine_expr = this.make_desugared_coroutine_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||
decl,
|
||||
|this| this.lower_block_expr(body),
|
||||
body.span,
|
||||
desugaring_kind,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
None,
|
||||
);
|
||||
|
||||
let hir_id = this.lower_node_id(closure_id);
|
||||
// FIXME(async_fn_track_caller): Can this be moved above?
|
||||
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||
this.maybe_forward_track_caller(body.span, fn_id, hir_id);
|
||||
let expr = hir::Expr { hir_id, kind: coroutine_expr, span: this.lower_span(body.span) };
|
||||
|
||||
(this.arena.alloc_from_iter(parameters), expr)
|
||||
(parameters, expr)
|
||||
})
|
||||
}
|
||||
|
||||
/// Lowers a desugared coroutine body after moving all of the arguments
|
||||
/// into the body. This is to make sure that the future actually owns the
|
||||
/// arguments that are passed to the function, and to ensure things like
|
||||
/// drop order are stable.
|
||||
pub fn lower_coroutine_body_with_moved_arguments(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>,
|
||||
body_span: Span,
|
||||
coroutine_kind: CoroutineKind,
|
||||
coroutine_source: hir::CoroutineSource,
|
||||
return_type_hint: Option<hir::FnRetTy<'hir>>,
|
||||
) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) {
|
||||
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
||||
let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
|
||||
|
||||
// Async function parameters are lowered into the closure body so that they are
|
||||
// captured and so that the drop order matches the equivalent non-async functions.
|
||||
//
|
||||
// from:
|
||||
//
|
||||
// async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
|
||||
// <body>
|
||||
// }
|
||||
//
|
||||
// into:
|
||||
//
|
||||
// fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
|
||||
// async move {
|
||||
// let __arg2 = __arg2;
|
||||
// let <pattern> = __arg2;
|
||||
// let __arg1 = __arg1;
|
||||
// let <pattern> = __arg1;
|
||||
// let __arg0 = __arg0;
|
||||
// let <pattern> = __arg0;
|
||||
// drop-temps { <body> } // see comments later in fn for details
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// If `<pattern>` is a simple ident, then it is lowered to a single
|
||||
// `let <pattern> = <pattern>;` statement as an optimization.
|
||||
//
|
||||
// Note that the body is embedded in `drop-temps`; an
|
||||
// equivalent desugaring would be `return { <body>
|
||||
// };`. The key point is that we wish to drop all the
|
||||
// let-bound variables and temporaries created in the body
|
||||
// (and its tail expression!) before we drop the
|
||||
// parameters (c.f. rust-lang/rust#64512).
|
||||
for (index, parameter) in decl.inputs.iter().enumerate() {
|
||||
let parameter = self.lower_param(parameter);
|
||||
let span = parameter.pat.span;
|
||||
|
||||
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
|
||||
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
|
||||
let (ident, is_simple_parameter) = match parameter.pat.kind {
|
||||
hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
|
||||
(ident, true)
|
||||
}
|
||||
// For `ref mut` or wildcard arguments, we can't reuse the binding, but
|
||||
// we can keep the same name for the parameter.
|
||||
// This lets rustdoc render it correctly in documentation.
|
||||
hir::PatKind::Binding(_, _, ident, _) => (ident, false),
|
||||
hir::PatKind::Wild => {
|
||||
(Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
|
||||
}
|
||||
_ => {
|
||||
// Replace the ident for bindings that aren't simple.
|
||||
let name = format!("__arg{index}");
|
||||
let ident = Ident::from_str(&name);
|
||||
|
||||
(ident, false)
|
||||
}
|
||||
};
|
||||
|
||||
let desugared_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
|
||||
|
||||
// Construct a parameter representing `__argN: <ty>` to replace the parameter of the
|
||||
// async function.
|
||||
//
|
||||
// If this is the simple case, this parameter will end up being the same as the
|
||||
// original parameter, but with a different pattern id.
|
||||
let stmt_attrs = self.attrs.get(¶meter.hir_id.local_id).copied();
|
||||
let (new_parameter_pat, new_parameter_id) = self.pat_ident(desugared_span, ident);
|
||||
let new_parameter = hir::Param {
|
||||
hir_id: parameter.hir_id,
|
||||
pat: new_parameter_pat,
|
||||
ty_span: self.lower_span(parameter.ty_span),
|
||||
span: self.lower_span(parameter.span),
|
||||
};
|
||||
|
||||
if is_simple_parameter {
|
||||
// If this is the simple case, then we only insert one statement that is
|
||||
// `let <pat> = <pat>;`. We re-use the original argument's pattern so that
|
||||
// `HirId`s are densely assigned.
|
||||
let expr = self.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let stmt = self.stmt_let_pat(
|
||||
stmt_attrs,
|
||||
desugared_span,
|
||||
Some(expr),
|
||||
parameter.pat,
|
||||
hir::LocalSource::AsyncFn,
|
||||
);
|
||||
statements.push(stmt);
|
||||
} else {
|
||||
// If this is not the simple case, then we construct two statements:
|
||||
//
|
||||
// ```
|
||||
// let __argN = __argN;
|
||||
// let <pat> = __argN;
|
||||
// ```
|
||||
//
|
||||
// The first statement moves the parameter into the closure and thus ensures
|
||||
// that the drop order is correct.
|
||||
//
|
||||
// The second statement creates the bindings that the user wrote.
|
||||
|
||||
// Construct the `let mut __argN = __argN;` statement. It must be a mut binding
|
||||
// because the user may have specified a `ref mut` binding in the next
|
||||
// statement.
|
||||
let (move_pat, move_id) =
|
||||
self.pat_ident_binding_mode(desugared_span, ident, hir::BindingAnnotation::MUT);
|
||||
let move_expr = self.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let move_stmt = self.stmt_let_pat(
|
||||
None,
|
||||
desugared_span,
|
||||
Some(move_expr),
|
||||
move_pat,
|
||||
hir::LocalSource::AsyncFn,
|
||||
);
|
||||
|
||||
// Construct the `let <pat> = __argN;` statement. We re-use the original
|
||||
// parameter's pattern so that `HirId`s are densely assigned.
|
||||
let pattern_expr = self.expr_ident(desugared_span, ident, move_id);
|
||||
let pattern_stmt = self.stmt_let_pat(
|
||||
stmt_attrs,
|
||||
desugared_span,
|
||||
Some(pattern_expr),
|
||||
parameter.pat,
|
||||
hir::LocalSource::AsyncFn,
|
||||
);
|
||||
|
||||
statements.push(move_stmt);
|
||||
statements.push(pattern_stmt);
|
||||
};
|
||||
|
||||
parameters.push(new_parameter);
|
||||
}
|
||||
|
||||
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
|
||||
// Create a block from the user's function body:
|
||||
let user_body = lower_body(this);
|
||||
|
||||
// Transform into `drop-temps { <user-body> }`, an expression:
|
||||
let desugared_span =
|
||||
this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
|
||||
let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body));
|
||||
|
||||
// As noted above, create the final block like
|
||||
//
|
||||
// ```
|
||||
// {
|
||||
// let $param_pattern = $raw_param;
|
||||
// ...
|
||||
// drop-temps { <user-body> }
|
||||
// }
|
||||
// ```
|
||||
let body = this.block_all(
|
||||
desugared_span,
|
||||
this.arena.alloc_from_iter(statements),
|
||||
Some(user_body),
|
||||
);
|
||||
|
||||
this.expr_block(body)
|
||||
};
|
||||
let desugaring_kind = match coroutine_kind {
|
||||
CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
|
||||
CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
|
||||
CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
|
||||
};
|
||||
let closure_id = coroutine_kind.closure_id();
|
||||
let coroutine_expr = self.make_desugared_coroutine_expr(
|
||||
// FIXME(async_closures): This should only move locals,
|
||||
// and not upvars. Capturing closure upvars by ref doesn't
|
||||
// work right now anyways, so whatever.
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
return_type_hint,
|
||||
body_span,
|
||||
desugaring_kind,
|
||||
coroutine_source,
|
||||
mkbody,
|
||||
);
|
||||
|
||||
let expr = hir::Expr {
|
||||
hir_id: self.lower_node_id(closure_id),
|
||||
kind: coroutine_expr,
|
||||
span: self.lower_span(body_span),
|
||||
};
|
||||
|
||||
(self.arena.alloc_from_iter(parameters), expr)
|
||||
}
|
||||
|
||||
fn lower_method_sig(
|
||||
&mut self,
|
||||
generics: &Generics,
|
||||
|
@ -109,6 +109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// return inner to be processed in next loop
|
||||
PatKind::Paren(inner) => pattern = inner,
|
||||
PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
|
||||
PatKind::Err(guar) => break hir::PatKind::Err(*guar),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1519,6 +1519,11 @@ impl<'a> State<'a> {
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::MacCall(m) => self.print_mac(m),
|
||||
PatKind::Err(_) => {
|
||||
self.popen();
|
||||
self.word("/*ERROR*/");
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::Pat(pat))
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
`async` non-`move` closures with parameters are currently not supported.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,edition2018,E0708
|
||||
```edition2018
|
||||
#![feature(async_closure)]
|
||||
|
||||
fn main() {
|
||||
let add_one = async |num: u8| { // error!
|
||||
let add_one = async |num: u8| {
|
||||
num + 1
|
||||
};
|
||||
}
|
||||
|
@ -1015,7 +1015,7 @@ impl<'hir> Pat<'hir> {
|
||||
|
||||
use PatKind::*;
|
||||
match self.kind {
|
||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
|
||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
|
||||
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
|
||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||
@ -1042,7 +1042,7 @@ impl<'hir> Pat<'hir> {
|
||||
|
||||
use PatKind::*;
|
||||
match self.kind {
|
||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {}
|
||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
|
||||
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
|
||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||
@ -1205,6 +1205,9 @@ pub enum PatKind<'hir> {
|
||||
/// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)])
|
||||
/// ```
|
||||
Slice(&'hir [Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [Pat<'hir>]),
|
||||
|
||||
/// A placeholder for a pattern that wasn't well formed in some way.
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
/// A statement.
|
||||
|
@ -655,7 +655,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
|
||||
walk_list!(visitor, visit_expr, lower_bound);
|
||||
walk_list!(visitor, visit_expr, upper_bound);
|
||||
}
|
||||
PatKind::Never | PatKind::Wild => (),
|
||||
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
|
||||
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
|
||||
walk_list!(visitor, visit_pat, prepatterns);
|
||||
walk_list!(visitor, visit_pat, slice_pattern);
|
||||
|
@ -681,7 +681,8 @@ fn resolve_local<'tcx>(
|
||||
| PatKind::Never
|
||||
| PatKind::Path(_)
|
||||
| PatKind::Lit(_)
|
||||
| PatKind::Range(_, _, _) => false,
|
||||
| PatKind::Range(_, _, _)
|
||||
| PatKind::Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1838,6 +1838,11 @@ impl<'a> State<'a> {
|
||||
self.commasep(Inconsistent, after, |s, p| s.print_pat(p));
|
||||
self.word("]");
|
||||
}
|
||||
PatKind::Err(_) => {
|
||||
self.popen();
|
||||
self.word("/*ERROR*/");
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::Pat(pat))
|
||||
}
|
||||
|
@ -293,49 +293,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
callee_node: &hir::ExprKind<'_>,
|
||||
callee_span: Span,
|
||||
) {
|
||||
let hir::ExprKind::Block(..) = callee_node else {
|
||||
// Only calls on blocks suggested here.
|
||||
return;
|
||||
};
|
||||
|
||||
let hir = self.tcx.hir();
|
||||
let parent_hir_id = hir.parent_id(hir_id);
|
||||
let parent_node = self.tcx.hir_node(parent_hir_id);
|
||||
if let (
|
||||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, kind, .. }),
|
||||
let fn_decl_span = if let hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
|
||||
..
|
||||
}) = hir.get_parent(hir_id)
|
||||
{
|
||||
fn_decl_span
|
||||
} else if let Some((
|
||||
_,
|
||||
hir::Node::Expr(&hir::Expr {
|
||||
hir_id: parent_hir_id,
|
||||
kind:
|
||||
hir::ExprKind::Closure(&hir::Closure {
|
||||
kind:
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Closure,
|
||||
)),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}),
|
||||
hir::ExprKind::Block(..),
|
||||
) = (parent_node, callee_node)
|
||||
)) = hir.parent_iter(hir_id).nth(3)
|
||||
{
|
||||
let fn_decl_span = if matches!(
|
||||
kind,
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Closure
|
||||
),)
|
||||
) {
|
||||
// Actually need to unwrap one more layer of HIR to get to
|
||||
// the _real_ closure...
|
||||
let async_closure = hir.parent_id(parent_hir_id);
|
||||
if let hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
|
||||
..
|
||||
}) = self.tcx.hir_node(async_closure)
|
||||
{
|
||||
fn_decl_span
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Actually need to unwrap one more layer of HIR to get to
|
||||
// the _real_ closure...
|
||||
let async_closure = hir.parent_id(parent_hir_id);
|
||||
if let hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
|
||||
..
|
||||
}) = self.tcx.hir_node(async_closure)
|
||||
{
|
||||
fn_decl_span
|
||||
};
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let start = fn_decl_span.shrink_to_lo();
|
||||
let end = callee_span.shrink_to_hi();
|
||||
err.multipart_suggestion(
|
||||
"if you meant to create this closure and immediately call it, surround the \
|
||||
let start = fn_decl_span.shrink_to_lo();
|
||||
let end = callee_span.shrink_to_hi();
|
||||
err.multipart_suggestion(
|
||||
"if you meant to create this closure and immediately call it, surround the \
|
||||
closure with parentheses",
|
||||
vec![(start, "(".to_string()), (end, ")".to_string())],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
vec![(start, "(".to_string()), (end, ")".to_string())],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
/// Give appropriate suggestion when encountering `[("a", 0) ("b", 1)]`, where the
|
||||
|
@ -754,16 +754,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
get_future_output(obligation.predicate, obligation.cause.span)
|
||||
})?
|
||||
}
|
||||
ty::Alias(ty::Projection, _) => {
|
||||
return Some(Ty::new_error_with_message(
|
||||
self.tcx,
|
||||
closure_span,
|
||||
"this projection should have been projected to an opaque type",
|
||||
));
|
||||
}
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
|
||||
.tcx
|
||||
.explicit_item_bounds(def_id)
|
||||
.iter_instantiated_copied(self.tcx, args)
|
||||
.find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
|
||||
ty::Error(_) => return Some(ret_ty),
|
||||
_ => span_bug!(
|
||||
closure_span,
|
||||
"async fn coroutine return type not an inference variable: {ret_ty}"
|
||||
),
|
||||
_ => {
|
||||
span_bug!(closure_span, "invalid async fn coroutine return type: {ret_ty:?}")
|
||||
}
|
||||
};
|
||||
|
||||
let output_ty = self.normalize(closure_span, output_ty);
|
||||
|
@ -458,11 +458,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
needs_to_be_read = true;
|
||||
}
|
||||
}
|
||||
PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => {
|
||||
PatKind::Or(_)
|
||||
| PatKind::Box(_)
|
||||
| PatKind::Ref(..)
|
||||
| PatKind::Wild
|
||||
| PatKind::Err(_) => {
|
||||
// If the PatKind is Or, Box, or Ref, the decision is made later
|
||||
// as these patterns contains subpatterns
|
||||
// If the PatKind is Wild, the decision is made based on the other patterns being
|
||||
// examined
|
||||
// If the PatKind is Wild or Err, the decision is made based on the other patterns
|
||||
// being examined
|
||||
}
|
||||
}
|
||||
})?
|
||||
|
@ -767,7 +767,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
| PatKind::Lit(..)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Never
|
||||
| PatKind::Wild => {
|
||||
| PatKind::Wild
|
||||
| PatKind::Err(_) => {
|
||||
// always ok
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin };
|
||||
|
||||
let ty = match pat.kind {
|
||||
PatKind::Wild => expected,
|
||||
PatKind::Wild | PatKind::Err(_) => expected,
|
||||
// FIXME(never_patterns): check the type is uninhabited. If that is not possible within
|
||||
// typeck, do that in a later phase.
|
||||
PatKind::Never => expected,
|
||||
@ -325,6 +325,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
PatKind::Ref(..) => AdjustMode::Reset,
|
||||
// A `_` pattern works with any expected type, so there's no need to do anything.
|
||||
PatKind::Wild
|
||||
// A malformed pattern doesn't have an expected type, so let's just accept any type.
|
||||
| PatKind::Err(_)
|
||||
// Bindings also work with whatever the expected type is,
|
||||
// and moreover if we peel references off, that will give us the wrong binding type.
|
||||
// Also, we can have a subpattern `binding @ pat`.
|
||||
@ -754,7 +756,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
| PatKind::Box(..)
|
||||
| PatKind::Ref(..)
|
||||
| PatKind::Lit(..)
|
||||
| PatKind::Range(..) => break 'block None,
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Err(_) => break 'block None,
|
||||
},
|
||||
|
||||
// Don't provide suggestions in other cases
|
||||
|
@ -13,7 +13,9 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::infer::unify_key::{
|
||||
ConstVariableOrigin, ConstVariableOriginKind, ConstVariableValue,
|
||||
};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
|
||||
use rustc_middle::ty::{self, InferConst};
|
||||
@ -178,17 +180,23 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
|
||||
}
|
||||
};
|
||||
printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
|
||||
let const_getter = move |ct_vid| {
|
||||
if infcx.probe_const_var(ct_vid).is_ok() {
|
||||
let const_getter = move |ct_vid| match infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.probe_value(ct_vid)
|
||||
{
|
||||
ConstVariableValue::Known { value: _ } => {
|
||||
warn!("resolved const var in error message");
|
||||
}
|
||||
if let ConstVariableOriginKind::ConstParameterDefinition(name, _) =
|
||||
infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind
|
||||
{
|
||||
return Some(name);
|
||||
} else {
|
||||
None
|
||||
}
|
||||
ConstVariableValue::Unknown { origin, universe: _ } => {
|
||||
if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = origin.kind {
|
||||
return Some(name);
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
printer.const_infer_name_resolver = Some(Box::new(const_getter));
|
||||
printer
|
||||
@ -303,7 +311,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
GenericArgKind::Const(ct) => {
|
||||
if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
|
||||
let origin =
|
||||
self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
|
||||
match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
|
||||
ConstVariableValue::Known { value } => {
|
||||
bug!("resolved infer var: {vid:?} {value}")
|
||||
}
|
||||
ConstVariableValue::Unknown { origin, universe: _ } => origin,
|
||||
};
|
||||
if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
|
||||
origin.kind
|
||||
{
|
||||
|
@ -146,14 +146,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
|
||||
let opt_ct = self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.probe_value(v)
|
||||
.val
|
||||
.known();
|
||||
let opt_ct =
|
||||
self.infcx.inner.borrow_mut().const_unification_table().probe_value(v).known();
|
||||
self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
|
||||
}
|
||||
ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc_middle::infer::unify_key::ConstVidKey;
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOriginKind, ConstVariableValue, ConstVidKey};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
|
||||
|
||||
@ -28,10 +28,17 @@ fn const_vars_since_snapshot<'tcx>(
|
||||
snapshot_var_len: usize,
|
||||
) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
|
||||
let range = vars_since_snapshot(table, snapshot_var_len);
|
||||
|
||||
(
|
||||
range.start.vid..range.end.vid,
|
||||
(range.start.index()..range.end.index())
|
||||
.map(|index| table.probe_value(ConstVid::from_u32(index)).origin)
|
||||
.map(|index| match table.probe_value(ConstVid::from_u32(index)) {
|
||||
ConstVariableValue::Known { value: _ } => ConstVariableOrigin {
|
||||
kind: ConstVariableOriginKind::MiscVariable,
|
||||
span: rustc_span::DUMMY_SP,
|
||||
},
|
||||
ConstVariableValue::Unknown { origin, universe: _ } => origin,
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ use rustc_data_structures::unify as ut;
|
||||
use rustc_errors::{DiagCtxt, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue};
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::{select, DefiningAnchor};
|
||||
@ -1086,7 +1086,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } })
|
||||
.new_key(ConstVariableValue::Unknown { origin, universe })
|
||||
.vid;
|
||||
ty::Const::new_var(self.tcx, vid, ty)
|
||||
}
|
||||
@ -1095,10 +1095,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
self.inner
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.new_key(ConstVarValue {
|
||||
origin,
|
||||
val: ConstVariableValue::Unknown { universe: self.universe() },
|
||||
})
|
||||
.new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
|
||||
.vid
|
||||
}
|
||||
|
||||
@ -1217,10 +1214,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.new_key(ConstVarValue {
|
||||
origin,
|
||||
val: ConstVariableValue::Unknown { universe: self.universe() },
|
||||
})
|
||||
.new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
|
||||
.vid;
|
||||
ty::Const::new_var(
|
||||
self.tcx,
|
||||
@ -1410,9 +1404,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
}
|
||||
|
||||
pub fn probe_const_var(&self, vid: ty::ConstVid) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
|
||||
match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
|
||||
match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
|
||||
ConstVariableValue::Known { value } => Ok(value),
|
||||
ConstVariableValue::Unknown { universe } => Err(universe),
|
||||
ConstVariableValue::Unknown { origin: _, universe } => Err(universe),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1709,7 +1703,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
// `ty::ConstKind::Infer(ty::InferConst::Var(v))`.
|
||||
//
|
||||
// Not `inlined_probe_value(v)` because this call site is colder.
|
||||
match self.inner.borrow_mut().const_unification_table().probe_value(v).val {
|
||||
match self.inner.borrow_mut().const_unification_table().probe_value(v) {
|
||||
ConstVariableValue::Unknown { .. } => false,
|
||||
ConstVariableValue::Known { .. } => true,
|
||||
}
|
||||
@ -1876,7 +1870,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.probe_value(vid)
|
||||
.val
|
||||
.known()
|
||||
.unwrap_or(ct),
|
||||
ty::ConstKind::Infer(InferConst::EffectVar(vid)) => self
|
||||
|
@ -30,14 +30,12 @@ use super::sub::Sub;
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
use rustc_middle::infer::canonical::OriginalQueryValues;
|
||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue};
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{AliasRelationDirection, TyVar};
|
||||
use rustc_middle::ty::{IntType, UintType};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CombineFields<'infcx, 'tcx> {
|
||||
@ -328,8 +326,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
let span =
|
||||
self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span;
|
||||
let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) {
|
||||
ConstVariableValue::Known { value } => {
|
||||
bug!("instantiating a known const var: {target_vid:?} {value} {ct}")
|
||||
}
|
||||
ConstVariableValue::Unknown { origin, universe: _ } => origin.span,
|
||||
};
|
||||
// FIXME(generic_const_exprs): Occurs check failures for unevaluated
|
||||
// constants and generic expressions are not yet handled correctly.
|
||||
let Generalization { value_may_be_infer: value, needs_wf: _ } = generalize::generalize(
|
||||
@ -340,16 +342,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
ty::Variance::Invariant,
|
||||
)?;
|
||||
|
||||
self.inner.borrow_mut().const_unification_table().union_value(
|
||||
target_vid,
|
||||
ConstVarValue {
|
||||
origin: ConstVariableOrigin {
|
||||
kind: ConstVariableOriginKind::ConstInference,
|
||||
span: DUMMY_SP,
|
||||
},
|
||||
val: ConstVariableValue::Known { value },
|
||||
},
|
||||
);
|
||||
self.inner
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.union_value(target_vid, ConstVariableValue::Known { value });
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ use std::mem;
|
||||
use rustc_data_structures::sso::SsoHashMap;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||
use rustc_middle::infer::unify_key::ConstVariableValue;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::visit::MaxUniverse;
|
||||
@ -431,22 +431,19 @@ where
|
||||
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let variable_table = &mut inner.const_unification_table();
|
||||
let var_value = variable_table.probe_value(vid);
|
||||
match var_value.val {
|
||||
match variable_table.probe_value(vid) {
|
||||
ConstVariableValue::Known { value: u } => {
|
||||
drop(inner);
|
||||
self.relate(u, u)
|
||||
}
|
||||
ConstVariableValue::Unknown { universe } => {
|
||||
ConstVariableValue::Unknown { origin, universe } => {
|
||||
if self.for_universe.can_name(universe) {
|
||||
Ok(c)
|
||||
} else {
|
||||
let new_var_id = variable_table
|
||||
.new_key(ConstVarValue {
|
||||
origin: var_value.origin,
|
||||
val: ConstVariableValue::Unknown {
|
||||
universe: self.for_universe,
|
||||
},
|
||||
.new_key(ConstVariableValue::Unknown {
|
||||
origin,
|
||||
universe: self.for_universe,
|
||||
})
|
||||
.vid;
|
||||
Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
|
||||
|
@ -1,12 +1,8 @@
|
||||
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use super::{FixupError, FixupResult, InferCtxt, Span};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use super::{FixupError, FixupResult, InferCtxt};
|
||||
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// OPPORTUNISTIC VAR RESOLVER
|
||||
|
||||
@ -104,88 +100,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// UNRESOLVED TYPE FINDER
|
||||
|
||||
/// The unresolved type **finder** walks a type searching for
|
||||
/// type variables that don't yet have a value. The first unresolved type is stored.
|
||||
/// It does not construct the fully resolved type (which might
|
||||
/// involve some hashing and so forth).
|
||||
pub struct UnresolvedTypeOrConstFinder<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> UnresolvedTypeOrConstFinder<'a, 'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
UnresolvedTypeOrConstFinder { infcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
|
||||
type BreakTy = (ty::Term<'tcx>, Option<Span>);
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
let t = self.infcx.shallow_resolve(t);
|
||||
if let ty::Infer(infer_ty) = *t.kind() {
|
||||
// Since we called `shallow_resolve` above, this must
|
||||
// be an (as yet...) unresolved inference variable.
|
||||
let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty {
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let ty_vars = &inner.type_variables();
|
||||
if let TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeParameterDefinition(_, _),
|
||||
span,
|
||||
} = ty_vars.var_origin(ty_vid)
|
||||
{
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
ControlFlow::Break((t.into(), ty_var_span))
|
||||
} else if !t.has_non_region_infer() {
|
||||
// All const/type variables in inference types must already be resolved,
|
||||
// no need to visit the contents.
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
// Otherwise, keep visiting.
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
let ct = self.infcx.shallow_resolve(ct);
|
||||
if let ty::ConstKind::Infer(i) = ct.kind() {
|
||||
// Since we called `shallow_resolve` above, this must
|
||||
// be an (as yet...) unresolved inference variable.
|
||||
let ct_var_span = if let ty::InferConst::Var(vid) = i {
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let ct_vars = &mut inner.const_unification_table();
|
||||
if let ConstVariableOrigin {
|
||||
span,
|
||||
kind: ConstVariableOriginKind::ConstParameterDefinition(_, _),
|
||||
} = ct_vars.probe_value(vid).origin
|
||||
{
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
ControlFlow::Break((ct.into(), ct_var_span))
|
||||
} else if !ct.has_non_region_infer() {
|
||||
// All const/type variables in inference types must already be resolved,
|
||||
// no need to visit the contents.
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
// Otherwise, keep visiting.
|
||||
ct.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// FULL TYPE RESOLUTION
|
||||
|
||||
|
@ -59,6 +59,9 @@ pub enum EscapeError {
|
||||
/// Non-ascii character in byte literal, byte string literal, or raw byte string literal.
|
||||
NonAsciiCharInByte,
|
||||
|
||||
// `\0` in a C string literal.
|
||||
NulInCStr,
|
||||
|
||||
/// After a line ending with '\', the next line contains whitespace
|
||||
/// characters that are not skipped.
|
||||
UnskippedWhitespaceWarning,
|
||||
@ -122,10 +125,20 @@ where
|
||||
{
|
||||
match mode {
|
||||
CStr => {
|
||||
unescape_non_raw_common(src, mode, callback);
|
||||
unescape_non_raw_common(src, mode, &mut |r, mut result| {
|
||||
if let Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) = result {
|
||||
result = Err(EscapeError::NulInCStr);
|
||||
}
|
||||
callback(r, result)
|
||||
});
|
||||
}
|
||||
RawCStr => {
|
||||
check_raw_common(src, mode, &mut |r, result| callback(r, result.map(CStrUnit::Char)));
|
||||
check_raw_common(src, mode, &mut |r, mut result| {
|
||||
if let Ok('\0') = result {
|
||||
result = Err(EscapeError::NulInCStr);
|
||||
}
|
||||
callback(r, result.map(CStrUnit::Char))
|
||||
});
|
||||
}
|
||||
Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(),
|
||||
}
|
||||
|
@ -1166,7 +1166,7 @@ impl EarlyLintPass for UnusedParens {
|
||||
// Do not lint on `(..)` as that will result in the other arms being useless.
|
||||
Paren(_)
|
||||
// The other cases do not contain sub-patterns.
|
||||
| Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
|
||||
| Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
|
||||
// These are list-like patterns; parens can always be removed.
|
||||
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
||||
self.check_unused_parens_pat(cx, p, false, false, keep_space);
|
||||
|
@ -120,7 +120,7 @@ pub enum ConstVariableOriginKind {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ConstVariableValue<'tcx> {
|
||||
Known { value: ty::Const<'tcx> },
|
||||
Unknown { universe: ty::UniverseIndex },
|
||||
Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex },
|
||||
}
|
||||
|
||||
impl<'tcx> ConstVariableValue<'tcx> {
|
||||
@ -134,12 +134,6 @@ impl<'tcx> ConstVariableValue<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ConstVarValue<'tcx> {
|
||||
pub origin: ConstVariableOrigin,
|
||||
pub val: ConstVariableValue<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||
pub struct ConstVidKey<'tcx> {
|
||||
pub vid: ty::ConstVid,
|
||||
@ -153,7 +147,7 @@ impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
|
||||
type Value = ConstVarValue<'tcx>;
|
||||
type Value = ConstVariableValue<'tcx>;
|
||||
#[inline]
|
||||
fn index(&self) -> u32 {
|
||||
self.vid.as_u32()
|
||||
@ -167,23 +161,23 @@ impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
|
||||
impl<'tcx> UnifyValue for ConstVariableValue<'tcx> {
|
||||
type Error = NoError;
|
||||
|
||||
fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
|
||||
Ok(match (value1.val, value2.val) {
|
||||
match (value1, value2) {
|
||||
(ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
|
||||
bug!("equating two const variables, both of which have known values")
|
||||
}
|
||||
|
||||
// If one side is known, prefer that one.
|
||||
(ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => value1,
|
||||
(ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => value2,
|
||||
(ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(value1),
|
||||
(ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(value2),
|
||||
|
||||
// If both sides are *unknown*, it hardly matters, does it?
|
||||
(
|
||||
ConstVariableValue::Unknown { universe: universe1 },
|
||||
ConstVariableValue::Unknown { universe: universe2 },
|
||||
ConstVariableValue::Unknown { origin, universe: universe1 },
|
||||
ConstVariableValue::Unknown { origin: _, universe: universe2 },
|
||||
) => {
|
||||
// If we unify two unbound variables, ?T and ?U, then whatever
|
||||
// value they wind up taking (which must be the same value) must
|
||||
@ -191,12 +185,9 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
|
||||
// universe is the minimum of the two universes, because that is
|
||||
// the one which contains the fewest names in scope.
|
||||
let universe = cmp::min(universe1, universe2);
|
||||
ConstVarValue {
|
||||
val: ConstVariableValue::Unknown { universe },
|
||||
origin: value1.origin,
|
||||
}
|
||||
Ok(ConstVariableValue::Unknown { origin, universe })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,15 +142,17 @@ fn dump_matched_mir_node<'tcx, F>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the file basename portion (without extension) of a filename path
|
||||
/// where we should dump a MIR representation output files.
|
||||
fn dump_file_basename<'tcx>(
|
||||
/// Returns the path to the filename where we should dump a given MIR.
|
||||
/// Also used by other bits of code (e.g., NLL inference) that dump
|
||||
/// graphviz data or other things.
|
||||
fn dump_path<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
extension: &str,
|
||||
pass_num: bool,
|
||||
pass_name: &str,
|
||||
disambiguator: &dyn Display,
|
||||
body: &Body<'tcx>,
|
||||
) -> String {
|
||||
) -> PathBuf {
|
||||
let source = body.source;
|
||||
let promotion_id = match source.promoted {
|
||||
Some(id) => format!("-{id:?}"),
|
||||
@ -186,45 +188,18 @@ fn dump_file_basename<'tcx>(
|
||||
_ => String::new(),
|
||||
};
|
||||
|
||||
format!(
|
||||
"{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}",
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the path to the filename where we should dump a given MIR.
|
||||
/// Also used by other bits of code (e.g., NLL inference) that dump
|
||||
/// graphviz data or other things.
|
||||
fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf {
|
||||
let mut file_path = PathBuf::new();
|
||||
file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir));
|
||||
|
||||
let file_name = format!("{basename}.{extension}",);
|
||||
let file_name = format!(
|
||||
"{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}",
|
||||
);
|
||||
|
||||
file_path.push(&file_name);
|
||||
|
||||
file_path
|
||||
}
|
||||
|
||||
/// Attempts to open the MIR dump file with the given name and extension.
|
||||
fn create_dump_file_with_basename(
|
||||
tcx: TyCtxt<'_>,
|
||||
file_basename: &str,
|
||||
extension: &str,
|
||||
) -> io::Result<io::BufWriter<fs::File>> {
|
||||
let file_path = dump_path(tcx, file_basename, extension);
|
||||
if let Some(parent) = file_path.parent() {
|
||||
fs::create_dir_all(parent).map_err(|e| {
|
||||
io::Error::new(
|
||||
e.kind(),
|
||||
format!("IO error creating MIR dump directory: {parent:?}; {e}"),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| {
|
||||
io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}"))
|
||||
})?))
|
||||
}
|
||||
|
||||
/// Attempts to open a file where we should dump a given MIR or other
|
||||
/// bit of MIR-related data. Used by `mir-dump`, but also by other
|
||||
/// bits of code (e.g., NLL inference) that dump graphviz data or
|
||||
@ -237,11 +212,18 @@ pub fn create_dump_file<'tcx>(
|
||||
disambiguator: &dyn Display,
|
||||
body: &Body<'tcx>,
|
||||
) -> io::Result<io::BufWriter<fs::File>> {
|
||||
create_dump_file_with_basename(
|
||||
tcx,
|
||||
&dump_file_basename(tcx, pass_num, pass_name, disambiguator, body),
|
||||
extension,
|
||||
)
|
||||
let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, body);
|
||||
if let Some(parent) = file_path.parent() {
|
||||
fs::create_dir_all(parent).map_err(|e| {
|
||||
io::Error::new(
|
||||
e.kind(),
|
||||
format!("IO error creating MIR dump directory: {parent:?}; {e}"),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| {
|
||||
io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}"))
|
||||
})?))
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -345,6 +345,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
|
||||
|
||||
hir::PatKind::Err(guar) => PatKind::Error(guar),
|
||||
};
|
||||
|
||||
Box::new(Pat { span, ty, kind })
|
||||
|
@ -616,6 +616,8 @@ parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable
|
||||
|
||||
parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
|
||||
|
||||
parse_nul_in_c_str = null characters in C string literals are not supported
|
||||
|
||||
parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
|
||||
parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
|
||||
parse_out_of_range_hex_escape = out of range hex escape
|
||||
|
@ -2163,6 +2163,11 @@ pub enum UnescapeError {
|
||||
#[subdiagnostic]
|
||||
suggestion: MoreThanOneCharSugg,
|
||||
},
|
||||
#[diag(parse_nul_in_c_str)]
|
||||
NulInCStr {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
@ -262,6 +262,9 @@ pub(crate) fn emit_unescape_error(
|
||||
EscapeError::LoneSlash => {
|
||||
dcx.emit_err(UnescapeError::LoneSlash(err_span));
|
||||
}
|
||||
EscapeError::NulInCStr => {
|
||||
dcx.emit_err(UnescapeError::NulInCStr { span: err_span });
|
||||
}
|
||||
EscapeError::UnskippedWhitespaceWarning => {
|
||||
let (c, char_span) = last_char();
|
||||
dcx.emit_warn(UnescapeError::UnskippedWhitespace {
|
||||
|
@ -303,7 +303,8 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||
Ref,
|
||||
Lit,
|
||||
Range,
|
||||
Slice
|
||||
Slice,
|
||||
Err
|
||||
]
|
||||
);
|
||||
hir_visit::walk_pat(self, p)
|
||||
@ -576,7 +577,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||
Rest,
|
||||
Never,
|
||||
Paren,
|
||||
MacCall
|
||||
MacCall,
|
||||
Err
|
||||
]
|
||||
);
|
||||
ast_visit::walk_pat(self, p)
|
||||
|
@ -75,8 +75,6 @@ session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be u
|
||||
|
||||
session_not_supported = not supported
|
||||
|
||||
session_nul_in_c_str = null characters in C string literals are not supported
|
||||
|
||||
session_octal_float_literal_not_supported = octal float literal is not supported
|
||||
|
||||
session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
|
||||
|
@ -6,7 +6,7 @@ use rustc_errors::{
|
||||
error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan,
|
||||
};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
|
||||
|
||||
use crate::parse::ParseSess;
|
||||
@ -346,13 +346,6 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_nul_in_c_str)]
|
||||
pub(crate) struct NulInCStr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
|
||||
// Checks if `s` looks like i32 or u1234 etc.
|
||||
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
|
||||
@ -432,12 +425,6 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
|
||||
};
|
||||
dcx.emit_err(IntLiteralTooLarge { span, limit });
|
||||
}
|
||||
LitError::NulInCStr(range) => {
|
||||
let lo = BytePos(span.lo().0 + range.start as u32 + 2);
|
||||
let hi = BytePos(span.lo().0 + range.end as u32 + 2);
|
||||
let span = span.with_lo(lo).with_hi(hi);
|
||||
dcx.emit_err(NulInCStr { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,35 +190,120 @@ where
|
||||
stable_mir::compiler_interface::run(&tables, || init(&tables, f))
|
||||
}
|
||||
|
||||
/// Instantiate and run the compiler with the provided arguments and callback.
|
||||
///
|
||||
/// The callback will be invoked after the compiler ran all its analyses, but before code generation.
|
||||
/// Note that this macro accepts two different formats for the callback:
|
||||
/// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow<B, C>`
|
||||
/// ```ignore(needs-extern-crate)
|
||||
/// # extern crate rustc_driver;
|
||||
/// # extern crate rustc_interface;
|
||||
/// # #[macro_use]
|
||||
/// # extern crate rustc_smir;
|
||||
/// # extern crate stable_mir;
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # use std::ops::ControlFlow;
|
||||
/// # use stable_mir::CompilerError;
|
||||
/// fn analyze_code() -> ControlFlow<(), ()> {
|
||||
/// // Your code goes in here.
|
||||
/// # ControlFlow::Continue(())
|
||||
/// }
|
||||
/// # let args = vec!["--verbose".to_string()];
|
||||
/// let result = run!(args, analyze_code);
|
||||
/// # assert_eq!(result, Err(CompilerError::Skipped))
|
||||
/// # }
|
||||
/// ```
|
||||
/// 2. A closure expression:
|
||||
/// ```ignore(needs-extern-crate)
|
||||
/// # extern crate rustc_driver;
|
||||
/// # extern crate rustc_interface;
|
||||
/// # #[macro_use]
|
||||
/// # extern crate rustc_smir;
|
||||
/// # extern crate stable_mir;
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # use std::ops::ControlFlow;
|
||||
/// # use stable_mir::CompilerError;
|
||||
/// fn analyze_code(extra_args: Vec<String>) -> ControlFlow<(), ()> {
|
||||
/// # let _ = extra_args;
|
||||
/// // Your code goes in here.
|
||||
/// # ControlFlow::Continue(())
|
||||
/// }
|
||||
/// # let args = vec!["--verbose".to_string()];
|
||||
/// # let extra_args = vec![];
|
||||
/// let result = run!(args, || analyze_code(extra_args));
|
||||
/// # assert_eq!(result, Err(CompilerError::Skipped))
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! run {
|
||||
($args:expr, $callback:expr) => {
|
||||
run!($args, tcx, $callback)
|
||||
($args:expr, $callback_fn:ident) => {
|
||||
run_driver!($args, || $callback_fn())
|
||||
};
|
||||
($args:expr, $tcx:ident, $callback:expr) => {{
|
||||
($args:expr, $callback:expr) => {
|
||||
run_driver!($args, $callback)
|
||||
};
|
||||
}
|
||||
|
||||
/// Instantiate and run the compiler with the provided arguments and callback.
|
||||
///
|
||||
/// This is similar to `run` but it invokes the callback with the compiler's `TyCtxt`,
|
||||
/// which can be used to invoke internal APIs.
|
||||
#[macro_export]
|
||||
macro_rules! run_with_tcx {
|
||||
($args:expr, $callback_fn:ident) => {
|
||||
run_driver!($args, |tcx| $callback_fn(tcx), with_tcx)
|
||||
};
|
||||
($args:expr, $callback:expr) => {
|
||||
run_driver!($args, $callback, with_tcx)
|
||||
};
|
||||
}
|
||||
|
||||
/// Optionally include an ident. This is needed due to macro hygiene.
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! optional {
|
||||
(with_tcx $ident:ident) => {
|
||||
$ident
|
||||
};
|
||||
}
|
||||
|
||||
/// Prefer using [run!] and [run_with_tcx] instead.
|
||||
///
|
||||
/// This macro implements the instantiation of a StableMIR driver, and it will invoke
|
||||
/// the given callback after the compiler analyses.
|
||||
///
|
||||
/// The third argument determines whether the callback requires `tcx` as an argument.
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! run_driver {
|
||||
($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{
|
||||
use rustc_driver::{Callbacks, Compilation, RunCompiler};
|
||||
use rustc_interface::{interface, Queries};
|
||||
use stable_mir::CompilerError;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub struct StableMir<B = (), C = ()>
|
||||
pub struct StableMir<B = (), C = (), F = fn($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C>>
|
||||
where
|
||||
B: Send,
|
||||
C: Send,
|
||||
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
|
||||
{
|
||||
args: Vec<String>,
|
||||
callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>,
|
||||
callback: Option<F>,
|
||||
result: Option<ControlFlow<B, C>>,
|
||||
}
|
||||
|
||||
impl<B, C> StableMir<B, C>
|
||||
impl<B, C, F> StableMir<B, C, F>
|
||||
where
|
||||
B: Send,
|
||||
C: Send,
|
||||
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
|
||||
{
|
||||
/// Creates a new `StableMir` instance, with given test_function and arguments.
|
||||
pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>) -> Self {
|
||||
StableMir { args, callback, result: None }
|
||||
pub fn new(args: Vec<String>, callback: F) -> Self {
|
||||
StableMir { args, callback: Some(callback), result: None }
|
||||
}
|
||||
|
||||
/// Runs the compiler against given target and tests it with `test_function`
|
||||
@ -238,10 +323,11 @@ macro_rules! run {
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, C> Callbacks for StableMir<B, C>
|
||||
impl<B, C, F> Callbacks for StableMir<B, C, F>
|
||||
where
|
||||
B: Send,
|
||||
C: Send,
|
||||
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
|
||||
{
|
||||
/// Called after analysis. Return value instructs the compiler whether to
|
||||
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
|
||||
@ -251,20 +337,24 @@ macro_rules! run {
|
||||
queries: &'tcx Queries<'tcx>,
|
||||
) -> Compilation {
|
||||
queries.global_ctxt().unwrap().enter(|tcx| {
|
||||
rustc_internal::run(tcx, || {
|
||||
self.result = Some((self.callback)(tcx));
|
||||
})
|
||||
.unwrap();
|
||||
if self.result.as_ref().is_some_and(|val| val.is_continue()) {
|
||||
Compilation::Continue
|
||||
if let Some(callback) = self.callback.take() {
|
||||
rustc_internal::run(tcx, || {
|
||||
self.result = Some(callback($(optional!($with_tcx tcx))?));
|
||||
})
|
||||
.unwrap();
|
||||
if self.result.as_ref().is_some_and(|val| val.is_continue()) {
|
||||
Compilation::Continue
|
||||
} else {
|
||||
Compilation::Stop
|
||||
}
|
||||
} else {
|
||||
Compilation::Stop
|
||||
Compilation::Continue
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
StableMir::new($args, |$tcx| $callback).run()
|
||||
StableMir::new($args, $callback).run()
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -312,7 +312,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
|
||||
|
||||
Symbol::intern(&match p.kind {
|
||||
// FIXME(never_patterns): does this make sense?
|
||||
PatKind::Wild | PatKind::Never | PatKind::Struct(..) => return kw::Underscore,
|
||||
PatKind::Wild | PatKind::Err(_) | PatKind::Never | PatKind::Struct(..) => {
|
||||
return kw::Underscore;
|
||||
}
|
||||
PatKind::Binding(_, _, ident, _) => return ident.name,
|
||||
PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
|
||||
PatKind::Or(pats) => {
|
||||
|
@ -45,50 +45,72 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
// For functions, with explicitly defined types, don't warn.
|
||||
// XXXkhuey maybe we should?
|
||||
if let ExprKind::Closure(Closure {
|
||||
kind:
|
||||
ClosureKind::Coroutine(CoroutineKind::Desugared(
|
||||
CoroutineDesugaring::Async,
|
||||
CoroutineSource::Block | CoroutineSource::Closure,
|
||||
)),
|
||||
let ExprKind::Closure(Closure {
|
||||
kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, kind)),
|
||||
body: body_id,
|
||||
..
|
||||
}) = expr.kind
|
||||
{
|
||||
if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
|
||||
let typeck_results = cx.tcx.typeck_body(*body_id);
|
||||
let body = cx.tcx.hir().body(*body_id);
|
||||
let expr_ty = typeck_results.expr_ty(body.value);
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
|
||||
let return_expr_span = match &body.value.kind {
|
||||
// XXXkhuey there has to be a better way.
|
||||
ExprKind::Block(block, _) => block.expr.map(|e| e.span),
|
||||
ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(return_expr_span) = return_expr_span {
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
ASYNC_YIELDS_ASYNC,
|
||||
body.value.hir_id,
|
||||
let body_expr = match kind {
|
||||
CoroutineSource::Fn => {
|
||||
// For functions, with explicitly defined types, don't warn.
|
||||
// XXXkhuey maybe we should?
|
||||
return;
|
||||
},
|
||||
CoroutineSource::Block => cx.tcx.hir().body(*body_id).value,
|
||||
CoroutineSource::Closure => {
|
||||
// Like `async fn`, async closures are wrapped in an additional block
|
||||
// to move all of the closure's arguments into the future.
|
||||
|
||||
let async_closure_body = cx.tcx.hir().body(*body_id).value;
|
||||
let ExprKind::Block(block, _) = async_closure_body.kind else {
|
||||
return;
|
||||
};
|
||||
let Some(block_expr) = block.expr else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::DropTemps(body_expr) = block_expr.kind else {
|
||||
return;
|
||||
};
|
||||
body_expr
|
||||
},
|
||||
};
|
||||
|
||||
let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let typeck_results = cx.tcx.typeck_body(*body_id);
|
||||
let expr_ty = typeck_results.expr_ty(body_expr);
|
||||
|
||||
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
|
||||
let return_expr_span = match &body_expr.kind {
|
||||
// XXXkhuey there has to be a better way.
|
||||
ExprKind::Block(block, _) => block.expr.map(|e| e.span),
|
||||
ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(return_expr_span) = return_expr_span {
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
ASYNC_YIELDS_ASYNC,
|
||||
body_expr.hir_id,
|
||||
return_expr_span,
|
||||
"an async construct yields a type which is itself awaitable",
|
||||
|db| {
|
||||
db.span_label(body_expr.span, "outer async construct");
|
||||
db.span_label(return_expr_span, "awaitable value not awaited");
|
||||
db.span_suggestion(
|
||||
return_expr_span,
|
||||
"an async construct yields a type which is itself awaitable",
|
||||
|db| {
|
||||
db.span_label(body.value.span, "outer async construct");
|
||||
db.span_label(return_expr_span, "awaitable value not awaited");
|
||||
db.span_suggestion(
|
||||
return_expr_span,
|
||||
"consider awaiting this value",
|
||||
format!("{}.await", snippet(cx, return_expr_span, "..")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
},
|
||||
"consider awaiting this value",
|
||||
format!("{}.await", snippet(cx, return_expr_span, "..")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,8 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
|
||||
| PatKind::Binding(..)
|
||||
| PatKind::Wild
|
||||
| PatKind::Never
|
||||
| PatKind::Or(_) => false,
|
||||
| PatKind::Or(_)
|
||||
| PatKind::Err(_) => false,
|
||||
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
|
||||
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
|
||||
PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
|
||||
|
@ -11,7 +11,7 @@ use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, P
|
||||
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::{ErrorGuaranteed, Symbol};
|
||||
|
||||
use super::MATCH_SAME_ARMS;
|
||||
|
||||
@ -167,6 +167,8 @@ enum NormalizedPat<'a> {
|
||||
/// contains everything afterwards. Note that either side, or both sides, may contain zero
|
||||
/// patterns.
|
||||
Slice(&'a [Self], Option<&'a [Self]>),
|
||||
/// A placeholder for a pattern that wasn't well formed in some way.
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -329,6 +331,7 @@ impl<'a> NormalizedPat<'a> {
|
||||
arena.alloc_from_iter(front.iter().map(|pat| Self::from_pat(cx, arena, pat))),
|
||||
wild_pat.map(|_| &*arena.alloc_from_iter(back.iter().map(|pat| Self::from_pat(cx, arena, pat)))),
|
||||
),
|
||||
PatKind::Err(guar) => Self::Err(guar),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,9 @@ use clippy_utils::sugg::Sugg;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
|
||||
use rustc_hir::{intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Node};
|
||||
use rustc_hir::{
|
||||
intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
@ -166,10 +168,22 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
|
||||
if coroutine_kind.is_async()
|
||||
&& let hir::ExprKind::Closure(closure) = body.kind
|
||||
{
|
||||
let async_closure_body = cx.tcx.hir().body(closure.body);
|
||||
// Like `async fn`, async closures are wrapped in an additional block
|
||||
// to move all of the closure's arguments into the future.
|
||||
|
||||
let async_closure_body = cx.tcx.hir().body(closure.body).value;
|
||||
let ExprKind::Block(block, _) = async_closure_body.kind else {
|
||||
return;
|
||||
};
|
||||
let Some(block_expr) = block.expr else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::DropTemps(body_expr) = block_expr.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
// `async x` is a syntax error, so it becomes `async { x }`
|
||||
if !matches!(async_closure_body.value.kind, hir::ExprKind::Block(_, _)) {
|
||||
if !matches!(body_expr.kind, hir::ExprKind::Block(_, _)) {
|
||||
hint = hint.blockify();
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|
||||
// Therefore they are not some form of constructor `C`,
|
||||
// with which a pattern `C(p_0)` may be formed,
|
||||
// which we would want to join with other `C(p_j)`s.
|
||||
Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_)
|
||||
Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_)
|
||||
// Skip immutable refs, as grouping them saves few characters,
|
||||
// and almost always requires adding parens (increasing noisiness).
|
||||
// In the case of only two patterns, replacement adds net characters.
|
||||
|
@ -710,6 +710,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||
self.slice(start, |pat| self.pat(pat));
|
||||
self.slice(end, |pat| self.pat(pat));
|
||||
},
|
||||
PatKind::Err(_) => kind!("Err"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1007,7 +1007,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||
}
|
||||
e.hash(&mut self.s);
|
||||
},
|
||||
PatKind::Never | PatKind::Wild => {},
|
||||
PatKind::Never | PatKind::Wild | PatKind::Err(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1733,6 +1733,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
||||
},
|
||||
}
|
||||
},
|
||||
PatKind::Err(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,11 @@ if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_
|
||||
&& expr2 = &cx.tcx.hir().body(body_id1).value
|
||||
&& let ExprKind::Block(block, None) = expr2.kind
|
||||
&& block.stmts.is_empty()
|
||||
&& block.expr.is_none()
|
||||
&& let Some(trailing_expr) = block.expr
|
||||
&& let ExprKind::DropTemps(expr3) = trailing_expr.kind
|
||||
&& let ExprKind::Block(block1, None) = expr3.kind
|
||||
&& block1.stmts.is_empty()
|
||||
&& block1.expr.is_none()
|
||||
{
|
||||
// report your lint here
|
||||
}
|
||||
|
@ -369,6 +369,7 @@ fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str {
|
||||
"non-ASCII character in byte string literal"
|
||||
}
|
||||
EscapeError::NonAsciiCharInByte => "non-ASCII character in raw byte string literal",
|
||||
EscapeError::NulInCStr => "null character in C string literal",
|
||||
EscapeError::UnskippedWhitespaceWarning => "",
|
||||
EscapeError::MultipleSkippedLinesWarning => "",
|
||||
}
|
||||
|
@ -106,6 +106,9 @@ fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str,
|
||||
EE::NonAsciiCharInByte => {
|
||||
"Byte literals must not contain non-ASCII characters"
|
||||
}
|
||||
EE::NulInCStr => {
|
||||
"C strings literals must not contain null characters"
|
||||
}
|
||||
EE::UnskippedWhitespaceWarning => "Whitespace after this escape is not skipped",
|
||||
EE::MultipleSkippedLinesWarning => "Multiple lines are skipped by this escape",
|
||||
|
||||
|
@ -40,9 +40,11 @@ pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
|
||||
|
||||
fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
|
||||
match pat.kind {
|
||||
ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Lit(_) => {
|
||||
true
|
||||
}
|
||||
ast::PatKind::Rest
|
||||
| ast::PatKind::Never
|
||||
| ast::PatKind::Wild
|
||||
| ast::PatKind::Err(_)
|
||||
| ast::PatKind::Lit(_) => true,
|
||||
ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
|
||||
ast::PatKind::Struct(..)
|
||||
| ast::PatKind::MacCall(..)
|
||||
@ -274,6 +276,7 @@ impl Rewrite for Pat {
|
||||
PatKind::Paren(ref pat) => pat
|
||||
.rewrite(context, shape.offset_left(1)?.sub_width(1)?)
|
||||
.map(|inner_pat| format!("({})", inner_pat)),
|
||||
PatKind::Err(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,14 +12,12 @@
|
||||
#![feature(ascii_char, ascii_char_variants)]
|
||||
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
|
||||
use stable_mir::mir::mono::Instance;
|
||||
@ -32,7 +30,7 @@ use std::ops::ControlFlow;
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||
fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_stable_mir() -> ControlFlow<()> {
|
||||
// Find items in the local crate.
|
||||
let items = stable_mir::all_local_items();
|
||||
|
||||
@ -117,7 +115,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_stable_mir(tcx)).unwrap();
|
||||
run!(args, test_stable_mir).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -14,14 +14,12 @@
|
||||
#![feature(ascii_char, ascii_char_variants)]
|
||||
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::crate_def::CrateDef;
|
||||
use stable_mir::mir::alloc::GlobalAlloc;
|
||||
@ -40,7 +38,7 @@ use std::ops::ControlFlow;
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||
fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_stable_mir() -> ControlFlow<()> {
|
||||
// Find items in the local crate.
|
||||
let items = stable_mir::all_local_items();
|
||||
check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap());
|
||||
@ -230,7 +228,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_stable_mir(tcx)).unwrap();
|
||||
run!(args, test_stable_mir).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -11,7 +11,6 @@
|
||||
#![feature(assert_matches)]
|
||||
#![feature(control_flow_enum)]
|
||||
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
@ -20,7 +19,6 @@ extern crate stable_mir;
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
use mir::{mono::Instance, TerminatorKind::*};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy};
|
||||
use stable_mir::*;
|
||||
@ -30,7 +28,7 @@ use std::ops::ControlFlow;
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||
fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_stable_mir() -> ControlFlow<()> {
|
||||
let entry = stable_mir::entry_fn().unwrap();
|
||||
let main_fn = Instance::try_from(entry).unwrap();
|
||||
assert_eq!(main_fn.name(), "main");
|
||||
@ -113,7 +111,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_stable_mir(tcx)).unwrap();
|
||||
run!(args, test_stable_mir).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -11,7 +11,6 @@
|
||||
#![feature(assert_matches)]
|
||||
#![feature(control_flow_enum)]
|
||||
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
@ -19,7 +18,6 @@ extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use mir::{mono::Instance, TerminatorKind::*};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::ty::{RigidTy, TyKind};
|
||||
use stable_mir::*;
|
||||
@ -29,7 +27,7 @@ use std::ops::ControlFlow;
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||
fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_stable_mir() -> ControlFlow<()> {
|
||||
let items = stable_mir::all_local_items();
|
||||
|
||||
// Get all items and split generic vs monomorphic items.
|
||||
@ -96,7 +94,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_stable_mir(tcx)).unwrap();
|
||||
run!(args, test_stable_mir).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -11,14 +11,12 @@
|
||||
#![feature(assert_matches)]
|
||||
#![feature(control_flow_enum)]
|
||||
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::*;
|
||||
use std::io::Write;
|
||||
@ -27,7 +25,7 @@ use std::ops::ControlFlow;
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||
fn test_item_kind(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_item_kind() -> ControlFlow<()> {
|
||||
let items = stable_mir::all_local_items();
|
||||
assert_eq!(items.len(), 4);
|
||||
// Constructor item.
|
||||
@ -59,7 +57,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_item_kind(tcx)).unwrap();
|
||||
run!(args, test_item_kind).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -11,14 +11,12 @@
|
||||
#![feature(assert_matches)]
|
||||
#![feature(control_flow_enum)]
|
||||
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::CrateDef;
|
||||
use std::collections::HashSet;
|
||||
@ -83,7 +81,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, test_traits()).unwrap();
|
||||
run!(args, test_traits).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -12,14 +12,12 @@
|
||||
#![feature(assert_matches)]
|
||||
#![feature(control_flow_enum)]
|
||||
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::ty::{RigidTy, TyKind, Ty, };
|
||||
use stable_mir::mir::{Body, MirVisitor, FieldIdx, Place, ProjectionElem, visit::{Location,
|
||||
@ -30,7 +28,7 @@ use std::ops::ControlFlow;
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||
fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_stable_mir() -> ControlFlow<()> {
|
||||
let main_fn = stable_mir::entry_fn();
|
||||
let body = main_fn.unwrap().body();
|
||||
let mut visitor = PlaceVisitor{ body: &body, tested: false};
|
||||
@ -87,7 +85,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_stable_mir(tcx)).unwrap();
|
||||
run!(args, test_stable_mir).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -10,14 +10,12 @@
|
||||
#![feature(rustc_private)]
|
||||
#![feature(assert_matches)]
|
||||
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use std::io::Write;
|
||||
|
||||
@ -32,33 +30,41 @@ fn main() {
|
||||
test_continue(args.clone());
|
||||
test_break(args.clone());
|
||||
test_failed(args.clone());
|
||||
test_skipped(args);
|
||||
test_skipped(args.clone());
|
||||
test_captured(args)
|
||||
}
|
||||
|
||||
fn test_continue(args: Vec<String>) {
|
||||
let result = run!(args, ControlFlow::Continue::<(), bool>(true));
|
||||
let result = run!(args, || ControlFlow::Continue::<(), bool>(true));
|
||||
assert_eq!(result, Ok(true));
|
||||
}
|
||||
|
||||
fn test_break(args: Vec<String>) {
|
||||
let result = run!(args, ControlFlow::Break::<bool, i32>(false));
|
||||
let result = run!(args, || ControlFlow::Break::<bool, i32>(false));
|
||||
assert_eq!(result, Err(stable_mir::CompilerError::Interrupted(false)));
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
fn test_skipped(mut args: Vec<String>) {
|
||||
args.push("--version".to_string());
|
||||
let result = run!(args, unreachable!() as ControlFlow<()>);
|
||||
let result = run!(args, || unreachable!() as ControlFlow<()>);
|
||||
assert_eq!(result, Err(stable_mir::CompilerError::Skipped));
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
fn test_failed(mut args: Vec<String>) {
|
||||
args.push("--cfg=broken".to_string());
|
||||
let result = run!(args, unreachable!() as ControlFlow<()>);
|
||||
let result = run!(args, || unreachable!() as ControlFlow<()>);
|
||||
assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed));
|
||||
}
|
||||
|
||||
/// Test that we are able to pass a closure and set the return according to the captured value.
|
||||
fn test_captured(args: Vec<String>) {
|
||||
let captured = "10".to_string();
|
||||
let result = run!(args, || ControlFlow::Continue::<(), usize>(captured.len()));
|
||||
assert_eq!(result, Ok(captured.len()));
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
let mut file = std::fs::File::create(path)?;
|
||||
write!(
|
||||
|
@ -12,7 +12,6 @@
|
||||
#![feature(control_flow_enum)]
|
||||
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
@ -20,7 +19,6 @@ extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::ItemKind;
|
||||
use stable_mir::crate_def::CrateDef;
|
||||
@ -33,7 +31,7 @@ use std::ops::ControlFlow;
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||
fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_stable_mir() -> ControlFlow<()> {
|
||||
// Get the local crate using stable_mir API.
|
||||
let local = stable_mir::local_crate();
|
||||
assert_eq!(&local.name, CRATE_NAME);
|
||||
@ -194,7 +192,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_stable_mir(tcx)).unwrap();
|
||||
run!(args, test_stable_mir).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -12,14 +12,12 @@
|
||||
#![feature(control_flow_enum)]
|
||||
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::crate_def::CrateDef;
|
||||
use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
|
||||
@ -32,7 +30,7 @@ use std::ops::ControlFlow;
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
/// Tests projections within Place objects
|
||||
fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_place_projections() -> ControlFlow<()> {
|
||||
let items = stable_mir::all_local_items();
|
||||
let body = get_item(&items, (ItemKind::Fn, "projections")).unwrap().body();
|
||||
assert_eq!(body.blocks.len(), 4);
|
||||
@ -159,7 +157,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_place_projections(tcx)).unwrap();
|
||||
run!(args, test_place_projections).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -26,7 +26,7 @@ use std::ops::ControlFlow;
|
||||
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_translation(_tcx: TyCtxt) -> ControlFlow<()> {
|
||||
let main_fn = stable_mir::entry_fn().unwrap();
|
||||
let body = main_fn.body();
|
||||
let orig_ty = body.locals()[0].ty;
|
||||
@ -48,7 +48,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_translation(tcx)).unwrap();
|
||||
run_with_tcx!(args, test_translation).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -11,7 +11,6 @@
|
||||
#![feature(assert_matches)]
|
||||
#![feature(control_flow_enum)]
|
||||
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
@ -19,7 +18,6 @@ extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::*;
|
||||
use stable_mir::mir::MirVisitor;
|
||||
@ -28,7 +26,7 @@ use std::ops::ControlFlow;
|
||||
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
fn test_visitor(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
fn test_visitor() -> ControlFlow<()> {
|
||||
let main_fn = stable_mir::entry_fn();
|
||||
let main_body = main_fn.unwrap().body();
|
||||
let main_visitor = TestVisitor::collect(&main_body);
|
||||
@ -116,7 +114,7 @@ fn main() {
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_visitor(tcx)).unwrap();
|
||||
run!(args, test_visitor).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
|
@ -1,9 +1,10 @@
|
||||
// edition:2018
|
||||
// check-pass
|
||||
|
||||
#![feature(async_closure)]
|
||||
fn foo() -> Box<dyn std::future::Future<Output = u32>> {
|
||||
let x = 0u32;
|
||||
Box::new((async || x)())
|
||||
//~^ ERROR E0373
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -1,21 +0,0 @@
|
||||
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
|
||||
--> $DIR/async-borrowck-escaping-closure-error.rs:5:15
|
||||
|
|
||||
LL | Box::new((async || x)())
|
||||
| ^^^^^^^^ - `x` is borrowed here
|
||||
| |
|
||||
| may outlive borrowed value `x`
|
||||
|
|
||||
note: closure is returned here
|
||||
--> $DIR/async-borrowck-escaping-closure-error.rs:5:5
|
||||
|
|
||||
LL | Box::new((async || x)())
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
LL | Box::new((async move || x)())
|
||||
| ++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0373`.
|
12
tests/ui/async-await/inference_var_self_argument.rs
Normal file
12
tests/ui/async-await/inference_var_self_argument.rs
Normal file
@ -0,0 +1,12 @@
|
||||
//! This is a regression test for an ICE.
|
||||
// edition: 2021
|
||||
|
||||
trait Foo {
|
||||
async fn foo(self: &dyn Foo) {
|
||||
//~^ ERROR: `Foo` cannot be made into an object
|
||||
//~| ERROR invalid `self` parameter type: &dyn Foo
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
28
tests/ui/async-await/inference_var_self_argument.stderr
Normal file
28
tests/ui/async-await/inference_var_self_argument.stderr
Normal file
@ -0,0 +1,28 @@
|
||||
error[E0038]: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/inference_var_self_argument.rs:5:5
|
||||
|
|
||||
LL | async fn foo(self: &dyn Foo) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/inference_var_self_argument.rs:5:14
|
||||
|
|
||||
LL | trait Foo {
|
||||
| --- this trait cannot be made into an object...
|
||||
LL | async fn foo(self: &dyn Foo) {
|
||||
| ^^^ ...because method `foo` is `async`
|
||||
= help: consider moving `foo` to another trait
|
||||
|
||||
error[E0307]: invalid `self` parameter type: &dyn Foo
|
||||
--> $DIR/inference_var_self_argument.rs:5:24
|
||||
|
|
||||
LL | async fn foo(self: &dyn Foo) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: type of `self` must be `Self` or a type that dereferences to it
|
||||
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0038, E0307.
|
||||
For more information about an error, try `rustc --explain E0038`.
|
@ -1,8 +1,8 @@
|
||||
// edition:2018
|
||||
// check-pass
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
fn main() {
|
||||
let _ = async |x: u8| {};
|
||||
//~^ ERROR `async` non-`move` closures with parameters are not currently supported
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
error[E0708]: `async` non-`move` closures with parameters are not currently supported
|
||||
--> $DIR/no-params-non-move-async-closure.rs:6:13
|
||||
|
|
||||
LL | let _ = async |x: u8| {};
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0708`.
|
17
tests/ui/object-safety/erroneous_signature.rs
Normal file
17
tests/ui/object-safety/erroneous_signature.rs
Normal file
@ -0,0 +1,17 @@
|
||||
trait Foo {
|
||||
fn err(&self) -> MissingType;
|
||||
//~^ ERROR cannot find type `MissingType` in this scope
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
fn err(&self) -> MissingType {
|
||||
//~^ ERROR cannot find type `MissingType` in this scope
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn coerce(x: &i32) -> &dyn Foo {
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
15
tests/ui/object-safety/erroneous_signature.stderr
Normal file
15
tests/ui/object-safety/erroneous_signature.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0412]: cannot find type `MissingType` in this scope
|
||||
--> $DIR/erroneous_signature.rs:2:22
|
||||
|
|
||||
LL | fn err(&self) -> MissingType;
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `MissingType` in this scope
|
||||
--> $DIR/erroneous_signature.rs:7:22
|
||||
|
|
||||
LL | fn err(&self) -> MissingType {
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0412`.
|
Binary file not shown.
Binary file not shown.
@ -631,7 +631,7 @@ cc = ["@nnethercote"]
|
||||
[assign]
|
||||
warn_non_default_branch = true
|
||||
contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
|
||||
users_on_vacation = ["jyn514", "spastorino"]
|
||||
users_on_vacation = ["jyn514"]
|
||||
|
||||
[assign.adhoc_groups]
|
||||
compiler-team = [
|
||||
|
Loading…
Reference in New Issue
Block a user