Merge from rustc
This commit is contained in:
commit
035d86594d
482 changed files with 12465 additions and 6271 deletions
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
|
@ -288,6 +288,9 @@ jobs:
|
|||
- name: x86_64-gnu-aux
|
||||
os: ubuntu-20.04-4core-16gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-integration
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-debug
|
||||
os: ubuntu-20.04-8core-32gb
|
||||
env: {}
|
||||
|
|
|
|||
36
Cargo.lock
36
Cargo.lock
|
|
@ -795,10 +795,6 @@ dependencies = [
|
|||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coverage_test_macros"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.8"
|
||||
|
|
@ -3760,6 +3756,7 @@ dependencies = [
|
|||
"rustc_monomorphize",
|
||||
"rustc_parse",
|
||||
"rustc_passes",
|
||||
"rustc_pattern_analysis",
|
||||
"rustc_privacy",
|
||||
"rustc_query_system",
|
||||
"rustc_resolve",
|
||||
|
|
@ -4233,6 +4230,7 @@ dependencies = [
|
|||
"rustc_infer",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_pattern_analysis",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
|
|
@ -4266,7 +4264,6 @@ dependencies = [
|
|||
name = "rustc_mir_transform"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"coverage_test_macros",
|
||||
"either",
|
||||
"itertools",
|
||||
"rustc_arena",
|
||||
|
|
@ -4308,6 +4305,13 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_next_trait_solver"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_type_ir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_parse"
|
||||
version = "0.0.0"
|
||||
|
|
@ -4362,6 +4366,26 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_pattern_analysis"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_privacy"
|
||||
version = "0.0.0"
|
||||
|
|
@ -4492,6 +4516,7 @@ dependencies = [
|
|||
name = "rustc_smir"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_hir",
|
||||
"rustc_middle",
|
||||
|
|
@ -4576,6 +4601,7 @@ dependencies = [
|
|||
"rustc_infer",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_next_trait_solver",
|
||||
"rustc_parse_format",
|
||||
"rustc_query_system",
|
||||
"rustc_session",
|
||||
|
|
|
|||
|
|
@ -658,6 +658,24 @@ impl Pat {
|
|||
pub fn is_rest(&self) -> bool {
|
||||
matches!(self.kind, PatKind::Rest)
|
||||
}
|
||||
|
||||
/// Whether this could be a never pattern, taking into account that a macro invocation can
|
||||
/// return a never pattern. Used to inform errors during parsing.
|
||||
pub fn could_be_never_pattern(&self) -> bool {
|
||||
let mut could_be_never_pattern = false;
|
||||
self.walk(&mut |pat| match &pat.kind {
|
||||
PatKind::Never | PatKind::MacCall(_) => {
|
||||
could_be_never_pattern = true;
|
||||
false
|
||||
}
|
||||
PatKind::Or(s) => {
|
||||
could_be_never_pattern = s.iter().all(|p| p.could_be_never_pattern());
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
});
|
||||
could_be_never_pattern
|
||||
}
|
||||
}
|
||||
|
||||
/// A single field in a struct pattern.
|
||||
|
|
@ -1080,8 +1098,8 @@ pub struct Arm {
|
|||
pub pat: P<Pat>,
|
||||
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`
|
||||
pub guard: Option<P<Expr>>,
|
||||
/// Match arm body.
|
||||
pub body: P<Expr>,
|
||||
/// Match arm body. Omitted if the pattern is a never pattern.
|
||||
pub body: Option<P<Expr>>,
|
||||
pub span: Span,
|
||||
pub id: NodeId,
|
||||
pub is_placeholder: bool,
|
||||
|
|
@ -1311,7 +1329,7 @@ pub struct Closure {
|
|||
pub binder: ClosureBinder,
|
||||
pub capture_clause: CaptureBy,
|
||||
pub constness: Const,
|
||||
pub coro_kind: Option<CoroutineKind>,
|
||||
pub coroutine_kind: Option<CoroutineKind>,
|
||||
pub movability: Movability,
|
||||
pub fn_decl: P<FnDecl>,
|
||||
pub body: P<Expr>,
|
||||
|
|
@ -1516,6 +1534,7 @@ pub enum ExprKind {
|
|||
pub enum GenBlockKind {
|
||||
Async,
|
||||
Gen,
|
||||
AsyncGen,
|
||||
}
|
||||
|
||||
impl fmt::Display for GenBlockKind {
|
||||
|
|
@ -1529,6 +1548,7 @@ impl GenBlockKind {
|
|||
match self {
|
||||
GenBlockKind::Async => "async",
|
||||
GenBlockKind::Gen => "gen",
|
||||
GenBlockKind::AsyncGen => "async gen",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2413,10 +2433,12 @@ pub enum Unsafe {
|
|||
/// Iterator`.
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
|
||||
pub enum CoroutineKind {
|
||||
/// `async`, which evaluates to `impl Future`
|
||||
/// `async`, which returns an `impl Future`
|
||||
Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
/// `gen`, which evaluates to `impl Iterator`
|
||||
/// `gen`, which returns an `impl Iterator`
|
||||
Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
/// `async gen`, which returns an `impl AsyncIterator`
|
||||
AsyncGen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
}
|
||||
|
||||
impl CoroutineKind {
|
||||
|
|
@ -2428,12 +2450,23 @@ impl CoroutineKind {
|
|||
matches!(self, CoroutineKind::Gen { .. })
|
||||
}
|
||||
|
||||
pub fn closure_id(self) -> NodeId {
|
||||
match self {
|
||||
CoroutineKind::Async { closure_id, .. }
|
||||
| CoroutineKind::Gen { closure_id, .. }
|
||||
| CoroutineKind::AsyncGen { closure_id, .. } => closure_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// In this case this is an `async` or `gen` return, the `NodeId` for the generated `impl Trait`
|
||||
/// item.
|
||||
pub fn return_id(self) -> (NodeId, Span) {
|
||||
match self {
|
||||
CoroutineKind::Async { return_impl_trait_id, span, .. }
|
||||
| CoroutineKind::Gen { return_impl_trait_id, span, .. } => (return_impl_trait_id, span),
|
||||
| CoroutineKind::Gen { return_impl_trait_id, span, .. }
|
||||
| CoroutineKind::AsyncGen { return_impl_trait_id, span, .. } => {
|
||||
(return_impl_trait_id, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2838,7 +2871,7 @@ pub struct FnHeader {
|
|||
/// The `unsafe` keyword, if any
|
||||
pub unsafety: Unsafe,
|
||||
/// Whether this is `async`, `gen`, or nothing.
|
||||
pub coro_kind: Option<CoroutineKind>,
|
||||
pub coroutine_kind: Option<CoroutineKind>,
|
||||
/// The `const` keyword, if any
|
||||
pub constness: Const,
|
||||
/// The `extern` keyword and corresponding ABI string, if any
|
||||
|
|
@ -2848,9 +2881,9 @@ pub struct FnHeader {
|
|||
impl FnHeader {
|
||||
/// Does this function header have any qualifiers or is it empty?
|
||||
pub fn has_qualifiers(&self) -> bool {
|
||||
let Self { unsafety, coro_kind, constness, ext } = self;
|
||||
let Self { unsafety, coroutine_kind, constness, ext } = self;
|
||||
matches!(unsafety, Unsafe::Yes(_))
|
||||
|| coro_kind.is_some()
|
||||
|| coroutine_kind.is_some()
|
||||
|| matches!(constness, Const::Yes(_))
|
||||
|| !matches!(ext, Extern::None)
|
||||
}
|
||||
|
|
@ -2858,7 +2891,12 @@ impl FnHeader {
|
|||
|
||||
impl Default for FnHeader {
|
||||
fn default() -> FnHeader {
|
||||
FnHeader { unsafety: Unsafe::No, coro_kind: None, constness: Const::No, ext: Extern::None }
|
||||
FnHeader {
|
||||
unsafety: Unsafe::No,
|
||||
coroutine_kind: None,
|
||||
constness: Const::No,
|
||||
ext: Extern::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,8 +121,8 @@ pub trait MutVisitor: Sized {
|
|||
noop_visit_fn_decl(d, self);
|
||||
}
|
||||
|
||||
fn visit_coro_kind(&mut self, a: &mut CoroutineKind) {
|
||||
noop_visit_coro_kind(a, self);
|
||||
fn visit_coroutine_kind(&mut self, a: &mut CoroutineKind) {
|
||||
noop_visit_coroutine_kind(a, self);
|
||||
}
|
||||
|
||||
fn visit_closure_binder(&mut self, b: &mut ClosureBinder) {
|
||||
|
|
@ -453,7 +453,7 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
|
|||
vis.visit_id(id);
|
||||
vis.visit_pat(pat);
|
||||
visit_opt(guard, |guard| vis.visit_expr(guard));
|
||||
vis.visit_expr(body);
|
||||
visit_opt(body, |body| vis.visit_expr(body));
|
||||
vis.visit_span(span);
|
||||
smallvec![arm]
|
||||
}
|
||||
|
|
@ -871,10 +871,11 @@ pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis:
|
|||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_coro_kind<T: MutVisitor>(coro_kind: &mut CoroutineKind, vis: &mut T) {
|
||||
match coro_kind {
|
||||
pub fn noop_visit_coroutine_kind<T: MutVisitor>(coroutine_kind: &mut CoroutineKind, vis: &mut T) {
|
||||
match coroutine_kind {
|
||||
CoroutineKind::Async { span, closure_id, return_impl_trait_id }
|
||||
| CoroutineKind::Gen { span, closure_id, return_impl_trait_id } => {
|
||||
| CoroutineKind::Gen { span, closure_id, return_impl_trait_id }
|
||||
| CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id } => {
|
||||
vis.visit_span(span);
|
||||
vis.visit_id(closure_id);
|
||||
vis.visit_id(return_impl_trait_id);
|
||||
|
|
@ -1171,9 +1172,9 @@ fn visit_const_item<T: MutVisitor>(
|
|||
}
|
||||
|
||||
pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
|
||||
let FnHeader { unsafety, coro_kind, constness, ext: _ } = header;
|
||||
let FnHeader { unsafety, coroutine_kind, constness, ext: _ } = header;
|
||||
visit_constness(constness, vis);
|
||||
coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind));
|
||||
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
||||
visit_unsafety(unsafety, vis);
|
||||
}
|
||||
|
||||
|
|
@ -1407,7 +1408,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
|||
binder,
|
||||
capture_clause,
|
||||
constness,
|
||||
coro_kind,
|
||||
coroutine_kind,
|
||||
movability: _,
|
||||
fn_decl,
|
||||
body,
|
||||
|
|
@ -1416,7 +1417,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
|||
}) => {
|
||||
vis.visit_closure_binder(binder);
|
||||
visit_constness(constness, vis);
|
||||
coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind));
|
||||
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
||||
vis.visit_capture_by(capture_clause);
|
||||
vis.visit_fn_decl(fn_decl);
|
||||
vis.visit_expr(body);
|
||||
|
|
|
|||
|
|
@ -861,7 +861,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||
ExprKind::Closure(box Closure {
|
||||
binder,
|
||||
capture_clause,
|
||||
coro_kind: _,
|
||||
coroutine_kind: _,
|
||||
constness: _,
|
||||
movability: _,
|
||||
fn_decl,
|
||||
|
|
@ -951,7 +951,7 @@ pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) {
|
|||
pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
|
||||
visitor.visit_pat(&arm.pat);
|
||||
walk_list!(visitor, visit_expr, &arm.guard);
|
||||
visitor.visit_expr(&arm.body);
|
||||
walk_list!(visitor, visit_expr, &arm.body);
|
||||
walk_list!(visitor, visit_attribute, &arm.attrs);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ ast_lowering_invalid_register =
|
|||
ast_lowering_invalid_register_class =
|
||||
invalid register class `{$reg_class}`: {$error}
|
||||
|
||||
ast_lowering_match_arm_with_no_body =
|
||||
`match` arm with no body
|
||||
.suggestion = add a body after the pattern
|
||||
|
||||
ast_lowering_misplaced_assoc_ty_binding =
|
||||
associated type bounds are only allowed in where clauses and function signatures, not in {$position}
|
||||
|
||||
|
|
@ -104,6 +108,15 @@ ast_lowering_misplaced_impl_trait =
|
|||
ast_lowering_misplaced_relax_trait_bound =
|
||||
`?Trait` bounds are only permitted at the point where a type parameter is declared
|
||||
|
||||
ast_lowering_never_pattern_with_body =
|
||||
a never pattern is always unreachable
|
||||
.label = this will never be executed
|
||||
.suggestion = remove this expression
|
||||
|
||||
ast_lowering_never_pattern_with_guard =
|
||||
a guard on a never pattern will never be run
|
||||
.suggestion = remove this guard
|
||||
|
||||
ast_lowering_not_supported_for_lifetime_binder_async_closure =
|
||||
`for<...>` binders on `async` closures are not currently supported
|
||||
|
||||
|
|
|
|||
|
|
@ -340,6 +340,32 @@ pub struct NotSupportedForLifetimeBinderAsyncClosure {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_match_arm_with_no_body)]
|
||||
pub struct MatchArmWithNoBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_never_pattern_with_body)]
|
||||
pub struct NeverPatternWithBody {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_never_pattern_with_guard)]
|
||||
pub struct NeverPatternWithGuard {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_arbitrary_expression_in_pattern)]
|
||||
pub struct ArbitraryExpressionInPattern {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use super::errors::{
|
||||
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
||||
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
|
||||
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd,
|
||||
NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign,
|
||||
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
|
||||
NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
|
||||
UnderscoreExprLhsAssign,
|
||||
};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
|
||||
|
|
@ -13,6 +14,7 @@ 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};
|
||||
|
|
@ -195,22 +197,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
binder,
|
||||
capture_clause,
|
||||
constness,
|
||||
coro_kind,
|
||||
coroutine_kind,
|
||||
movability,
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span,
|
||||
fn_arg_span,
|
||||
}) => match coro_kind {
|
||||
Some(
|
||||
CoroutineKind::Async { closure_id, .. }
|
||||
| CoroutineKind::Gen { closure_id, .. },
|
||||
) => self.lower_expr_async_closure(
|
||||
}) => match coroutine_kind {
|
||||
Some(coroutine_kind) => self.lower_expr_coroutine_closure(
|
||||
binder,
|
||||
*capture_clause,
|
||||
e.id,
|
||||
hir_id,
|
||||
*closure_id,
|
||||
*coroutine_kind,
|
||||
fn_decl,
|
||||
body,
|
||||
*fn_decl_span,
|
||||
|
|
@ -324,6 +323,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Gen(capture_clause, block, GenBlockKind::AsyncGen) => self
|
||||
.make_async_gen_expr(
|
||||
*capture_clause,
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
ExprKind::Err => hir::ExprKind::Err(
|
||||
self.tcx.sess.span_delayed_bug(e.span, "lowered ExprKind::Err"),
|
||||
|
|
@ -549,7 +557,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
||||
let pat = self.lower_pat(&arm.pat);
|
||||
let guard = arm.guard.as_ref().map(|cond| {
|
||||
let mut guard = arm.guard.as_ref().map(|cond| {
|
||||
if let ExprKind::Let(pat, scrutinee, span, is_recovered) = &cond.kind {
|
||||
hir::Guard::IfLet(self.arena.alloc(hir::Let {
|
||||
hir_id: self.next_id(),
|
||||
|
|
@ -564,14 +572,43 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
});
|
||||
let hir_id = self.next_id();
|
||||
let span = self.lower_span(arm.span);
|
||||
self.lower_attrs(hir_id, &arm.attrs);
|
||||
hir::Arm {
|
||||
hir_id,
|
||||
pat,
|
||||
guard,
|
||||
body: self.lower_expr(&arm.body),
|
||||
span: self.lower_span(arm.span),
|
||||
}
|
||||
let is_never_pattern = pat.is_never_pattern();
|
||||
let body = if let Some(body) = &arm.body
|
||||
&& !is_never_pattern
|
||||
{
|
||||
self.lower_expr(body)
|
||||
} else {
|
||||
// Either `body.is_none()` or `is_never_pattern` here.
|
||||
if !is_never_pattern {
|
||||
let suggestion = span.shrink_to_hi();
|
||||
self.tcx.sess.emit_err(MatchArmWithNoBody { span, suggestion });
|
||||
} else if let Some(body) = &arm.body {
|
||||
self.tcx.sess.emit_err(NeverPatternWithBody { span: body.span });
|
||||
guard = None;
|
||||
} else if let Some(g) = &arm.guard {
|
||||
self.tcx.sess.emit_err(NeverPatternWithGuard { span: g.span });
|
||||
guard = None;
|
||||
}
|
||||
|
||||
// We add a fake `loop {}` arm body so that it typecks to `!`.
|
||||
// FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`.
|
||||
let block = self.arena.alloc(hir::Block {
|
||||
stmts: &[],
|
||||
expr: None,
|
||||
hir_id: self.next_id(),
|
||||
rules: hir::BlockCheckMode::DefaultBlock,
|
||||
span,
|
||||
targeted_by_break: false,
|
||||
});
|
||||
self.arena.alloc(hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::Loop(block, None, hir::LoopSource::Loop, span),
|
||||
span,
|
||||
})
|
||||
};
|
||||
hir::Arm { hir_id, pat, guard, body, span }
|
||||
}
|
||||
|
||||
/// Lower an `async` construct to a coroutine that implements `Future`.
|
||||
|
|
@ -597,7 +634,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// Resume argument type: `ResumeTy`
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
span,
|
||||
self.lower_span(span),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);
|
||||
|
|
@ -706,6 +743,87 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}))
|
||||
}
|
||||
|
||||
/// Lower a `async gen` construct to a generator that implements `AsyncIterator`.
|
||||
///
|
||||
/// This results in:
|
||||
///
|
||||
/// ```text
|
||||
/// static move? |_task_context| -> () {
|
||||
/// <body>
|
||||
/// }
|
||||
/// ```
|
||||
pub(super) fn make_async_gen_expr(
|
||||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
closure_node_id: NodeId,
|
||||
_yield_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
async_coroutine_source: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
|
||||
|
||||
// Resume argument type: `ResumeTy`
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
self.lower_span(span),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
);
|
||||
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);
|
||||
let input_ty = hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::Path(resume_ty),
|
||||
span: unstable_span,
|
||||
};
|
||||
|
||||
// The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
|
||||
let fn_decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: arena_vec![self; input_ty],
|
||||
output,
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
// Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
|
||||
let (pat, task_context_hid) = self.pat_ident_binding_mode(
|
||||
span,
|
||||
Ident::with_dummy_span(sym::_task_context),
|
||||
hir::BindingAnnotation::MUT,
|
||||
);
|
||||
let param = hir::Param {
|
||||
hir_id: self.next_id(),
|
||||
pat,
|
||||
ty_span: self.lower_span(span),
|
||||
span: self.lower_span(span),
|
||||
};
|
||||
let params = arena_vec![self; param];
|
||||
|
||||
let body = self.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(hir::CoroutineKind::AsyncGen(async_coroutine_source));
|
||||
|
||||
let old_ctx = this.task_context;
|
||||
this.task_context = Some(task_context_hid);
|
||||
let res = body(this);
|
||||
this.task_context = old_ctx;
|
||||
(params, res)
|
||||
});
|
||||
|
||||
// `static |_task_context| -> <ret_ty> { body }`:
|
||||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
fn_arg_span: None,
|
||||
movability: Some(hir::Movability::Static),
|
||||
constness: hir::Constness::NotConst,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
|
||||
/// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
|
||||
pub(super) fn maybe_forward_track_caller(
|
||||
|
|
@ -755,15 +873,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
/// ```
|
||||
fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
|
||||
let full_span = expr.span.to(await_kw_span);
|
||||
match self.coroutine_kind {
|
||||
Some(hir::CoroutineKind::Async(_)) => {}
|
||||
|
||||
let is_async_gen = match self.coroutine_kind {
|
||||
Some(hir::CoroutineKind::Async(_)) => false,
|
||||
Some(hir::CoroutineKind::AsyncGen(_)) => true,
|
||||
Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) | None => {
|
||||
return hir::ExprKind::Err(self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks {
|
||||
await_kw_span,
|
||||
item_span: self.current_item,
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None);
|
||||
let gen_future_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Await,
|
||||
|
|
@ -852,12 +973,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.stmt_expr(span, match_expr)
|
||||
};
|
||||
|
||||
// task_context = yield ();
|
||||
// Depending on `async` of `async gen`:
|
||||
// async - task_context = yield ();
|
||||
// async gen - task_context = yield ASYNC_GEN_PENDING;
|
||||
let yield_stmt = {
|
||||
let unit = self.expr_unit(span);
|
||||
let yielded = if is_async_gen {
|
||||
self.arena.alloc(self.expr_lang_item_path(span, hir::LangItem::AsyncGenPending))
|
||||
} else {
|
||||
self.expr_unit(span)
|
||||
};
|
||||
|
||||
let yield_expr = self.expr(
|
||||
span,
|
||||
hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr_hir_id) }),
|
||||
hir::ExprKind::Yield(yielded, hir::YieldSource::Await { expr: Some(expr_hir_id) }),
|
||||
);
|
||||
let yield_expr = self.arena.alloc(yield_expr);
|
||||
|
||||
|
|
@ -967,7 +1095,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
Some(movability)
|
||||
}
|
||||
Some(hir::CoroutineKind::Gen(_)) | Some(hir::CoroutineKind::Async(_)) => {
|
||||
Some(
|
||||
hir::CoroutineKind::Gen(_)
|
||||
| hir::CoroutineKind::Async(_)
|
||||
| hir::CoroutineKind::AsyncGen(_),
|
||||
) => {
|
||||
panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering");
|
||||
}
|
||||
None => {
|
||||
|
|
@ -994,18 +1126,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
(binder, params)
|
||||
}
|
||||
|
||||
fn lower_expr_async_closure(
|
||||
fn lower_expr_coroutine_closure(
|
||||
&mut self,
|
||||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
closure_hir_id: hir::HirId,
|
||||
inner_closure_id: NodeId,
|
||||
coroutine_kind: CoroutineKind,
|
||||
decl: &FnDecl,
|
||||
body: &Expr,
|
||||
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.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
|
||||
}
|
||||
|
|
@ -1474,8 +1610,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
|
||||
match self.coroutine_kind {
|
||||
Some(hir::CoroutineKind::Gen(_)) => {}
|
||||
let is_async_gen = match self.coroutine_kind {
|
||||
Some(hir::CoroutineKind::Gen(_)) => false,
|
||||
Some(hir::CoroutineKind::AsyncGen(_)) => true,
|
||||
Some(hir::CoroutineKind::Async(_)) => {
|
||||
return hir::ExprKind::Err(
|
||||
self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span }),
|
||||
|
|
@ -1491,14 +1628,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
.emit();
|
||||
}
|
||||
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine)
|
||||
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine);
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let expr =
|
||||
let mut yielded =
|
||||
opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
|
||||
|
||||
hir::ExprKind::Yield(expr, hir::YieldSource::Yield)
|
||||
if is_async_gen {
|
||||
// yield async_gen_ready($expr);
|
||||
yielded = self.expr_call_lang_item_fn(
|
||||
span,
|
||||
hir::LangItem::AsyncGenReady,
|
||||
std::slice::from_ref(yielded),
|
||||
);
|
||||
}
|
||||
|
||||
hir::ExprKind::Yield(yielded, hir::YieldSource::Yield)
|
||||
}
|
||||
|
||||
/// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
|
||||
|
|
|
|||
|
|
@ -206,19 +206,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// `impl Future<Output = T>` here because lower_body
|
||||
// only cares about the input argument patterns in the function
|
||||
// declaration (decl), not the return types.
|
||||
let coro_kind = header.coro_kind;
|
||||
let coroutine_kind = header.coroutine_kind;
|
||||
let body_id = this.lower_maybe_coroutine_body(
|
||||
span,
|
||||
hir_id,
|
||||
decl,
|
||||
coro_kind,
|
||||
coroutine_kind,
|
||||
body.as_deref(),
|
||||
);
|
||||
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) =
|
||||
this.lower_generics(generics, header.constness, id, &itctx, |this| {
|
||||
this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, coro_kind)
|
||||
this.lower_fn_decl(
|
||||
decl,
|
||||
id,
|
||||
*fn_sig_span,
|
||||
FnDeclKind::Fn,
|
||||
coroutine_kind,
|
||||
)
|
||||
});
|
||||
let sig = hir::FnSig {
|
||||
decl,
|
||||
|
|
@ -734,7 +740,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
sig,
|
||||
i.id,
|
||||
FnDeclKind::Trait,
|
||||
sig.header.coro_kind,
|
||||
sig.header.coroutine_kind,
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
|
||||
}
|
||||
|
|
@ -743,7 +749,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.span,
|
||||
hir_id,
|
||||
&sig.decl,
|
||||
sig.header.coro_kind,
|
||||
sig.header.coroutine_kind,
|
||||
Some(body),
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
|
|
@ -751,7 +757,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
sig,
|
||||
i.id,
|
||||
FnDeclKind::Trait,
|
||||
sig.header.coro_kind,
|
||||
sig.header.coroutine_kind,
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
|
||||
}
|
||||
|
|
@ -844,7 +850,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.span,
|
||||
hir_id,
|
||||
&sig.decl,
|
||||
sig.header.coro_kind,
|
||||
sig.header.coroutine_kind,
|
||||
body.as_deref(),
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
|
|
@ -852,7 +858,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
sig,
|
||||
i.id,
|
||||
if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
|
||||
sig.header.coro_kind,
|
||||
sig.header.coroutine_kind,
|
||||
);
|
||||
|
||||
(generics, hir::ImplItemKind::Fn(sig, body_id))
|
||||
|
|
@ -1023,17 +1029,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
span: Span,
|
||||
fn_id: hir::HirId,
|
||||
decl: &FnDecl,
|
||||
coro_kind: Option<CoroutineKind>,
|
||||
coroutine_kind: Option<CoroutineKind>,
|
||||
body: Option<&Block>,
|
||||
) -> hir::BodyId {
|
||||
let (Some(coro_kind), Some(body)) = (coro_kind, body) else {
|
||||
let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else {
|
||||
return self.lower_fn_body_block(span, decl, body);
|
||||
};
|
||||
let closure_id = match coro_kind {
|
||||
CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. } => {
|
||||
closure_id
|
||||
}
|
||||
};
|
||||
let closure_id = coroutine_kind.closure_id();
|
||||
|
||||
self.lower_body(|this| {
|
||||
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
||||
|
|
@ -1200,7 +1202,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
this.expr_block(body)
|
||||
};
|
||||
let coroutine_expr = match coro_kind {
|
||||
// FIXME(gen_blocks): Consider unifying the `make_*_expr` functions.
|
||||
let coroutine_expr = match coroutine_kind {
|
||||
CoroutineKind::Async { .. } => this.make_async_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
|
|
@ -1217,6 +1220,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
),
|
||||
CoroutineKind::AsyncGen { .. } => this.make_async_gen_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
),
|
||||
};
|
||||
|
||||
let hir_id = this.lower_node_id(closure_id);
|
||||
|
|
@ -1233,19 +1244,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
sig: &FnSig,
|
||||
id: NodeId,
|
||||
kind: FnDeclKind,
|
||||
coro_kind: Option<CoroutineKind>,
|
||||
coroutine_kind: Option<CoroutineKind>,
|
||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||
let header = self.lower_fn_header(sig.header);
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) =
|
||||
self.lower_generics(generics, sig.header.constness, id, &itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coro_kind)
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
|
||||
});
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
}
|
||||
|
||||
fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
|
||||
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coro_kind {
|
||||
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
|
||||
hir::IsAsync::Async(span)
|
||||
} else {
|
||||
hir::IsAsync::NotAsync
|
||||
|
|
@ -1371,6 +1382,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let host_param_parts = if let Const::Yes(span) = constness
|
||||
&& self.tcx.features().effects
|
||||
{
|
||||
let span = self.lower_span(span);
|
||||
let param_node_id = self.next_node_id();
|
||||
let hir_id = self.next_id();
|
||||
let def_id = self.create_def(
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ struct LoweringContext<'a, 'hir> {
|
|||
|
||||
allow_try_trait: Lrc<[Symbol]>,
|
||||
allow_gen_future: Lrc<[Symbol]>,
|
||||
allow_async_iterator: Lrc<[Symbol]>,
|
||||
|
||||
/// Mapping from generics `def_id`s to TAIT generics `def_id`s.
|
||||
/// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
|
||||
|
|
@ -176,6 +177,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
} else {
|
||||
[sym::gen_future].into()
|
||||
},
|
||||
// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
|
||||
// interact with `gen`/`async gen` blocks
|
||||
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
|
||||
generics_def_id_map: Default::default(),
|
||||
host_param_id: None,
|
||||
}
|
||||
|
|
@ -1675,7 +1679,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
duplicated_lifetime_node_id,
|
||||
lifetime.ident.name,
|
||||
DefKind::LifetimeParam,
|
||||
lifetime.ident.span,
|
||||
self.lower_span(lifetime.ident.span),
|
||||
);
|
||||
captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id);
|
||||
// FIXME: Instead of doing this, we could move this whole loop
|
||||
|
|
@ -1684,7 +1688,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
synthesized_lifetime_definitions.push((
|
||||
duplicated_lifetime_node_id,
|
||||
duplicated_lifetime_def_id,
|
||||
lifetime.ident,
|
||||
self.lower_ident(lifetime.ident),
|
||||
));
|
||||
|
||||
// Now make an arg that we can use for the generic params of the opaque tykind.
|
||||
|
|
@ -1900,13 +1904,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn_span: Span,
|
||||
) -> hir::FnRetTy<'hir> {
|
||||
let span = self.lower_span(fn_span);
|
||||
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
|
||||
|
||||
let opaque_ty_node_id = match coro {
|
||||
CoroutineKind::Async { return_impl_trait_id, .. }
|
||||
| CoroutineKind::Gen { return_impl_trait_id, .. } => return_impl_trait_id,
|
||||
let (opaque_ty_node_id, allowed_features) = match coro {
|
||||
CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None),
|
||||
CoroutineKind::Gen { return_impl_trait_id, .. } => (return_impl_trait_id, None),
|
||||
CoroutineKind::AsyncGen { return_impl_trait_id, .. } => {
|
||||
(return_impl_trait_id, Some(self.allow_async_iterator.clone()))
|
||||
}
|
||||
};
|
||||
|
||||
let opaque_ty_span =
|
||||
self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features);
|
||||
|
||||
let captured_lifetimes: Vec<_> = self
|
||||
.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
|
|
@ -1925,7 +1934,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let bound = this.lower_coroutine_fn_output_type_to_bound(
|
||||
output,
|
||||
coro,
|
||||
span,
|
||||
opaque_ty_span,
|
||||
ImplTraitContext::ReturnPositionOpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
||||
fn_kind,
|
||||
|
|
@ -1944,7 +1953,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
output: &FnRetTy,
|
||||
coro: CoroutineKind,
|
||||
span: Span,
|
||||
opaque_ty_span: Span,
|
||||
nested_impl_trait_context: ImplTraitContext,
|
||||
) -> hir::GenericBound<'hir> {
|
||||
// Compute the `T` in `Future<Output = T>` from the return type.
|
||||
|
|
@ -1960,20 +1969,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
// "<$assoc_ty_name = T>"
|
||||
let (assoc_ty_name, trait_lang_item) = match coro {
|
||||
CoroutineKind::Async { .. } => (hir::FN_OUTPUT_NAME, hir::LangItem::Future),
|
||||
CoroutineKind::Gen { .. } => (hir::ITERATOR_ITEM_NAME, hir::LangItem::Iterator),
|
||||
CoroutineKind::Async { .. } => (sym::Output, hir::LangItem::Future),
|
||||
CoroutineKind::Gen { .. } => (sym::Item, hir::LangItem::Iterator),
|
||||
CoroutineKind::AsyncGen { .. } => (sym::Item, hir::LangItem::AsyncIterator),
|
||||
};
|
||||
|
||||
let future_args = self.arena.alloc(hir::GenericArgs {
|
||||
args: &[],
|
||||
bindings: arena_vec![self; self.assoc_ty_binding(assoc_ty_name, span, output_ty)],
|
||||
bindings: arena_vec![self; self.assoc_ty_binding(assoc_ty_name, opaque_ty_span, output_ty)],
|
||||
parenthesized: hir::GenericArgsParentheses::No,
|
||||
span_ext: DUMMY_SP,
|
||||
});
|
||||
|
||||
hir::GenericBound::LangItemTrait(
|
||||
trait_lang_item,
|
||||
self.lower_span(span),
|
||||
opaque_ty_span,
|
||||
self.next_id(),
|
||||
future_args,
|
||||
)
|
||||
|
|
@ -2243,7 +2253,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
match c.value.kind {
|
||||
ExprKind::Underscore => {
|
||||
if self.tcx.features().generic_arg_infer {
|
||||
hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
|
||||
hir::ArrayLen::Infer(self.lower_node_id(c.id), self.lower_span(c.value.span))
|
||||
} else {
|
||||
feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
|
||||
};
|
||||
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
|
||||
let binding = self.assoc_ty_binding(hir::FN_OUTPUT_NAME, output_ty.span, output_ty);
|
||||
let binding = self.assoc_ty_binding(sym::Output, output_ty.span, output_ty);
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args,
|
||||
|
|
|
|||
|
|
@ -1271,14 +1271,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
// Functions cannot both be `const async` or `const gen`
|
||||
if let Some(&FnHeader {
|
||||
constness: Const::Yes(cspan),
|
||||
coro_kind:
|
||||
Some(
|
||||
CoroutineKind::Async { span: aspan, .. }
|
||||
| CoroutineKind::Gen { span: aspan, .. },
|
||||
),
|
||||
coroutine_kind: Some(coroutine_kind),
|
||||
..
|
||||
}) = fk.header()
|
||||
{
|
||||
let aspan = match coroutine_kind {
|
||||
CoroutineKind::Async { span: aspan, .. }
|
||||
| CoroutineKind::Gen { span: aspan, .. }
|
||||
| CoroutineKind::AsyncGen { span: aspan, .. } => aspan,
|
||||
};
|
||||
// FIXME(gen_blocks): Report a different error for `const gen`
|
||||
self.err_handler().emit_err(errors::ConstAndAsync {
|
||||
spans: vec![cspan, aspan],
|
||||
|
|
|
|||
|
|
@ -1490,14 +1490,18 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_coro_kind(&mut self, coro_kind: ast::CoroutineKind) {
|
||||
match coro_kind {
|
||||
fn print_coroutine_kind(&mut self, coroutine_kind: ast::CoroutineKind) {
|
||||
match coroutine_kind {
|
||||
ast::CoroutineKind::Gen { .. } => {
|
||||
self.word_nbsp("gen");
|
||||
}
|
||||
ast::CoroutineKind::Async { .. } => {
|
||||
self.word_nbsp("async");
|
||||
}
|
||||
ast::CoroutineKind::AsyncGen { .. } => {
|
||||
self.word_nbsp("async");
|
||||
self.word_nbsp("gen");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1690,7 +1694,7 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_fn_header_info(&mut self, header: ast::FnHeader) {
|
||||
self.print_constness(header.constness);
|
||||
header.coro_kind.map(|coro_kind| self.print_coro_kind(coro_kind));
|
||||
header.coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind));
|
||||
self.print_unsafety(header.unsafety);
|
||||
|
||||
match header.ext {
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ impl<'a> State<'a> {
|
|||
binder,
|
||||
capture_clause,
|
||||
constness,
|
||||
coro_kind,
|
||||
coroutine_kind,
|
||||
movability,
|
||||
fn_decl,
|
||||
body,
|
||||
|
|
@ -423,7 +423,7 @@ impl<'a> State<'a> {
|
|||
self.print_closure_binder(binder);
|
||||
self.print_constness(*constness);
|
||||
self.print_movability(*movability);
|
||||
coro_kind.map(|coro_kind| self.print_coro_kind(coro_kind));
|
||||
coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind));
|
||||
self.print_capture_clause(*capture_clause);
|
||||
|
||||
self.print_fn_params_and_ret(fn_decl, true);
|
||||
|
|
@ -631,28 +631,33 @@ impl<'a> State<'a> {
|
|||
self.print_expr(e);
|
||||
self.space();
|
||||
}
|
||||
self.word_space("=>");
|
||||
|
||||
match &arm.body.kind {
|
||||
ast::ExprKind::Block(blk, opt_label) => {
|
||||
if let Some(label) = opt_label {
|
||||
self.print_ident(label.ident);
|
||||
self.word_space(":");
|
||||
if let Some(body) = &arm.body {
|
||||
self.word_space("=>");
|
||||
|
||||
match &body.kind {
|
||||
ast::ExprKind::Block(blk, opt_label) => {
|
||||
if let Some(label) = opt_label {
|
||||
self.print_ident(label.ident);
|
||||
self.word_space(":");
|
||||
}
|
||||
|
||||
// The block will close the pattern's ibox.
|
||||
self.print_block_unclosed_indent(blk);
|
||||
|
||||
// If it is a user-provided unsafe block, print a comma after it.
|
||||
if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
|
||||
self.word(",");
|
||||
}
|
||||
}
|
||||
|
||||
// The block will close the pattern's ibox.
|
||||
self.print_block_unclosed_indent(blk);
|
||||
|
||||
// If it is a user-provided unsafe block, print a comma after it.
|
||||
if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
|
||||
_ => {
|
||||
self.end(); // Close the ibox for the pattern.
|
||||
self.print_expr(body);
|
||||
self.word(",");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.end(); // Close the ibox for the pattern.
|
||||
self.print_expr(&arm.body);
|
||||
self.word(",");
|
||||
}
|
||||
} else {
|
||||
self.word(",");
|
||||
}
|
||||
self.end(); // Close enclosing cbox.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,101 +11,88 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
|
||||
use rustc_mir_dataflow::ResultsVisitable;
|
||||
use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
|
||||
use rustc_mir_dataflow::{Analysis, Direction, Results};
|
||||
use rustc_mir_dataflow::{Analysis, AnalysisDomain, Results};
|
||||
use std::fmt;
|
||||
|
||||
use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext};
|
||||
|
||||
/// A tuple with named fields that can hold either the results or the transient state of the
|
||||
/// dataflow analyses used by the borrow checker.
|
||||
#[derive(Debug)]
|
||||
pub struct BorrowckAnalyses<B, U, E> {
|
||||
pub borrows: B,
|
||||
pub uninits: U,
|
||||
pub ever_inits: E,
|
||||
}
|
||||
|
||||
/// The results of the dataflow analyses used by the borrow checker.
|
||||
pub type BorrowckResults<'mir, 'tcx> = BorrowckAnalyses<
|
||||
Results<'tcx, Borrows<'mir, 'tcx>>,
|
||||
Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
|
||||
Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
|
||||
>;
|
||||
pub struct BorrowckResults<'mir, 'tcx> {
|
||||
pub(crate) borrows: Results<'tcx, Borrows<'mir, 'tcx>>,
|
||||
pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
|
||||
pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
|
||||
}
|
||||
|
||||
/// The transient state of the dataflow analyses used by the borrow checker.
|
||||
pub type BorrowckFlowState<'mir, 'tcx> =
|
||||
<BorrowckResults<'mir, 'tcx> as ResultsVisitable<'tcx>>::FlowState;
|
||||
|
||||
macro_rules! impl_visitable {
|
||||
( $(
|
||||
$T:ident { $( $field:ident : $A:ident ),* $(,)? }
|
||||
)* ) => { $(
|
||||
impl<'tcx, $($A),*, D: Direction> ResultsVisitable<'tcx> for $T<$( Results<'tcx, $A> ),*>
|
||||
where
|
||||
$( $A: Analysis<'tcx, Direction = D>, )*
|
||||
{
|
||||
type Direction = D;
|
||||
type FlowState = $T<$( $A::Domain ),*>;
|
||||
|
||||
fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
|
||||
$T {
|
||||
$( $field: self.$field.analysis.bottom_value(body) ),*
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_to_block_entry(
|
||||
&self,
|
||||
state: &mut Self::FlowState,
|
||||
block: BasicBlock,
|
||||
) {
|
||||
$( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )*
|
||||
}
|
||||
|
||||
fn reconstruct_before_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
$( self.$field.analysis
|
||||
.apply_before_statement_effect(&mut state.$field, stmt, loc); )*
|
||||
}
|
||||
|
||||
fn reconstruct_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
$( self.$field.analysis
|
||||
.apply_statement_effect(&mut state.$field, stmt, loc); )*
|
||||
}
|
||||
|
||||
fn reconstruct_before_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
$( self.$field.analysis
|
||||
.apply_before_terminator_effect(&mut state.$field, term, loc); )*
|
||||
}
|
||||
|
||||
fn reconstruct_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
$( self.$field.analysis
|
||||
.apply_terminator_effect(&mut state.$field, term, loc); )*
|
||||
}
|
||||
}
|
||||
)* }
|
||||
#[derive(Debug)]
|
||||
pub struct BorrowckFlowState<'mir, 'tcx> {
|
||||
pub(crate) borrows: <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
|
||||
pub(crate) uninits: <MaybeUninitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
|
||||
pub(crate) ever_inits: <EverInitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
|
||||
}
|
||||
|
||||
impl_visitable! {
|
||||
BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E }
|
||||
impl<'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'mir, 'tcx> {
|
||||
// All three analyses are forward, but we have to use just one here.
|
||||
type Direction = <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Direction;
|
||||
type FlowState = BorrowckFlowState<'mir, 'tcx>;
|
||||
|
||||
fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
|
||||
BorrowckFlowState {
|
||||
borrows: self.borrows.analysis.bottom_value(body),
|
||||
uninits: self.uninits.analysis.bottom_value(body),
|
||||
ever_inits: self.ever_inits.analysis.bottom_value(body),
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
|
||||
state.borrows.clone_from(&self.borrows.entry_set_for_block(block));
|
||||
state.uninits.clone_from(&self.uninits.entry_set_for_block(block));
|
||||
state.ever_inits.clone_from(&self.ever_inits.entry_set_for_block(block));
|
||||
}
|
||||
|
||||
fn reconstruct_before_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn reconstruct_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn reconstruct_before_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
}
|
||||
|
||||
fn reconstruct_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
|
|
@ -598,7 +585,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
|
||||
fn before_terminator_effect(
|
||||
&mut self,
|
||||
trans: &mut impl GenKill<Self::Idx>,
|
||||
trans: &mut Self::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
|
|
@ -625,7 +612,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
|
||||
fn call_return_effect(
|
||||
&mut self,
|
||||
_trans: &mut impl GenKill<Self::Idx>,
|
||||
_trans: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -2517,12 +2517,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
CoroutineKind::Gen(kind) => match kind {
|
||||
CoroutineSource::Block => "gen block",
|
||||
CoroutineSource::Closure => "gen closure",
|
||||
_ => bug!("gen block/closure expected, but gen function found."),
|
||||
CoroutineSource::Fn => {
|
||||
bug!("gen block/closure expected, but gen function found.")
|
||||
}
|
||||
},
|
||||
CoroutineKind::AsyncGen(kind) => match kind {
|
||||
CoroutineSource::Block => "async gen block",
|
||||
CoroutineSource::Closure => "async gen closure",
|
||||
CoroutineSource::Fn => {
|
||||
bug!("gen block/closure expected, but gen function found.")
|
||||
}
|
||||
},
|
||||
CoroutineKind::Async(async_kind) => match async_kind {
|
||||
CoroutineSource::Block => "async block",
|
||||
CoroutineSource::Closure => "async closure",
|
||||
_ => bug!("async block/closure expected, but async function found."),
|
||||
CoroutineSource::Fn => {
|
||||
bug!("async block/closure expected, but async function found.")
|
||||
}
|
||||
},
|
||||
CoroutineKind::Coroutine => "coroutine",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -684,7 +684,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
|
||||
};
|
||||
let mir_description = match hir.body(body).coroutine_kind {
|
||||
Some(hir::CoroutineKind::Async(gen)) => match gen {
|
||||
Some(hir::CoroutineKind::Async(src)) => match src {
|
||||
hir::CoroutineSource::Block => " of async block",
|
||||
hir::CoroutineSource::Closure => " of async closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
|
|
@ -701,7 +701,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
" of async function"
|
||||
}
|
||||
},
|
||||
Some(hir::CoroutineKind::Gen(gen)) => match gen {
|
||||
Some(hir::CoroutineKind::Gen(src)) => match src {
|
||||
hir::CoroutineSource::Block => " of gen block",
|
||||
hir::CoroutineSource::Closure => " of gen closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
|
|
@ -715,6 +715,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
" of gen function"
|
||||
}
|
||||
},
|
||||
|
||||
Some(hir::CoroutineKind::AsyncGen(src)) => match src {
|
||||
hir::CoroutineSource::Block => " of async gen block",
|
||||
hir::CoroutineSource::Closure => " of async gen closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
let parent_item =
|
||||
hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
.fn_decl()
|
||||
.expect("coroutine lowered from async gen fn should be in fn")
|
||||
.output;
|
||||
span = output.span();
|
||||
" of async gen function"
|
||||
}
|
||||
},
|
||||
Some(hir::CoroutineKind::Coroutine) => " of coroutine",
|
||||
None => " of closure",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ fn cs_partial_cmp(
|
|||
&& let Some(last) = arms.last_mut()
|
||||
&& let PatKind::Wild = last.pat.kind
|
||||
{
|
||||
last.body = expr2;
|
||||
last.body = Some(expr2);
|
||||
expr1
|
||||
} else {
|
||||
let eq_arm = cx.arm(
|
||||
|
|
|
|||
|
|
@ -541,12 +541,30 @@ fn check_test_signature(
|
|||
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
|
||||
}
|
||||
|
||||
if let Some(ast::CoroutineKind::Async { span, .. }) = f.sig.header.coro_kind {
|
||||
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" }));
|
||||
}
|
||||
|
||||
if let Some(ast::CoroutineKind::Gen { span, .. }) = f.sig.header.coro_kind {
|
||||
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "gen" }));
|
||||
if let Some(coroutine_kind) = f.sig.header.coroutine_kind {
|
||||
match coroutine_kind {
|
||||
ast::CoroutineKind::Async { span, .. } => {
|
||||
return Err(sd.emit_err(errors::TestBadFn {
|
||||
span: i.span,
|
||||
cause: span,
|
||||
kind: "async",
|
||||
}));
|
||||
}
|
||||
ast::CoroutineKind::Gen { span, .. } => {
|
||||
return Err(sd.emit_err(errors::TestBadFn {
|
||||
span: i.span,
|
||||
cause: span,
|
||||
kind: "gen",
|
||||
}));
|
||||
}
|
||||
ast::CoroutineKind::AsyncGen { span, .. } => {
|
||||
return Err(sd.emit_err(errors::TestBadFn {
|
||||
span: i.span,
|
||||
cause: span,
|
||||
kind: "async gen",
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the termination trait is active, the compiler will check that the output
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! Codegen `extern "platform-intrinsic"` intrinsics.
|
||||
|
||||
use cranelift_codegen::ir::immediates::Offset32;
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::abi::Endian;
|
||||
|
|
@ -1008,8 +1009,57 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
sym::simd_masked_load => {
|
||||
intrinsic_args!(fx, args => (mask, ptr, val); intrinsic);
|
||||
|
||||
let (val_lane_count, val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
|
||||
assert_eq!(val_lane_count, mask_lane_count);
|
||||
assert_eq!(val_lane_count, ret_lane_count);
|
||||
|
||||
let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap();
|
||||
let ret_lane_layout = fx.layout_of(ret_lane_ty);
|
||||
let ptr_val = ptr.load_scalar(fx);
|
||||
|
||||
for lane_idx in 0..ret_lane_count {
|
||||
let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
|
||||
let if_enabled = fx.bcx.create_block();
|
||||
let if_disabled = fx.bcx.create_block();
|
||||
let next = fx.bcx.create_block();
|
||||
let res_lane = fx.bcx.append_block_param(next, lane_clif_ty);
|
||||
|
||||
fx.bcx.ins().brif(mask_lane, if_enabled, &[], if_disabled, &[]);
|
||||
fx.bcx.seal_block(if_enabled);
|
||||
fx.bcx.seal_block(if_disabled);
|
||||
|
||||
fx.bcx.switch_to_block(if_enabled);
|
||||
let offset = lane_idx as i32 * lane_clif_ty.bytes() as i32;
|
||||
let res = fx.bcx.ins().load(
|
||||
lane_clif_ty,
|
||||
MemFlags::trusted(),
|
||||
ptr_val,
|
||||
Offset32::new(offset),
|
||||
);
|
||||
fx.bcx.ins().jump(next, &[res]);
|
||||
|
||||
fx.bcx.switch_to_block(if_disabled);
|
||||
fx.bcx.ins().jump(next, &[val_lane]);
|
||||
|
||||
fx.bcx.seal_block(next);
|
||||
fx.bcx.switch_to_block(next);
|
||||
|
||||
fx.bcx.ins().nop();
|
||||
|
||||
ret.place_lane(fx, lane_idx)
|
||||
.write_cvalue(fx, CValue::by_val(res_lane, ret_lane_layout));
|
||||
}
|
||||
}
|
||||
|
||||
sym::simd_scatter => {
|
||||
intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
|
||||
intrinsic_args!(fx, args => (mask, ptr, val); intrinsic);
|
||||
|
||||
let (val_lane_count, _val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
|
||||
|
|
|
|||
|
|
@ -569,5 +569,6 @@ fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
|
|||
TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
|
||||
TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
|
||||
TlsModel::LocalExec => gccjit::TlsModel::LocalExec,
|
||||
TlsModel::Emulated => gccjit::TlsModel::GlobalDynamic,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ impl OwnedTargetMachine {
|
|||
split_dwarf_file: &CStr,
|
||||
output_obj_file: &CStr,
|
||||
debug_info_compression: &CStr,
|
||||
force_emulated_tls: bool,
|
||||
use_emulated_tls: bool,
|
||||
args_cstr_buff: &[u8],
|
||||
) -> Result<Self, LlvmError<'static>> {
|
||||
assert!(args_cstr_buff.len() > 0);
|
||||
|
|
@ -71,7 +71,7 @@ impl OwnedTargetMachine {
|
|||
split_dwarf_file.as_ptr(),
|
||||
output_obj_file.as_ptr(),
|
||||
debug_info_compression.as_ptr(),
|
||||
force_emulated_tls,
|
||||
use_emulated_tls,
|
||||
args_cstr_buff.as_ptr() as *const c_char,
|
||||
args_cstr_buff.len(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, Switc
|
|||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::InnerSpan;
|
||||
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo};
|
||||
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
|
||||
|
||||
use crate::llvm::diagnostic::OptimizationDiagnosticKind;
|
||||
use libc::{c_char, c_int, c_uint, c_void, size_t};
|
||||
|
|
@ -223,7 +223,7 @@ pub fn target_machine_factory(
|
|||
|
||||
let path_mapping = sess.source_map().path_mapping().clone();
|
||||
|
||||
let force_emulated_tls = sess.target.force_emulated_tls;
|
||||
let use_emulated_tls = matches!(sess.tls_model(), TlsModel::Emulated);
|
||||
|
||||
// copy the exe path, followed by path all into one buffer
|
||||
// null terminating them so we can use them as null terminated strings
|
||||
|
|
@ -297,7 +297,7 @@ pub fn target_machine_factory(
|
|||
&split_dwarf_file,
|
||||
&output_obj_file,
|
||||
&debuginfo_compression,
|
||||
force_emulated_tls,
|
||||
use_emulated_tls,
|
||||
&args_cstr_buff,
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
|
|||
TlsModel::LocalDynamic => llvm::ThreadLocalMode::LocalDynamic,
|
||||
TlsModel::InitialExec => llvm::ThreadLocalMode::InitialExec,
|
||||
TlsModel::LocalExec => llvm::ThreadLocalMode::LocalExec,
|
||||
TlsModel::Emulated => llvm::ThreadLocalMode::GeneralDynamic,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
|
||||
let Coverage { kind } = coverage;
|
||||
match *kind {
|
||||
// Span markers are only meaningful during MIR instrumentation,
|
||||
// and have no effect during codegen.
|
||||
CoverageKind::SpanMarker => {}
|
||||
CoverageKind::CounterIncrement { id } => {
|
||||
func_coverage.mark_counter_id_seen(id);
|
||||
// We need to explicitly drop the `RefMut` before calling into `instrprof_increment`,
|
||||
|
|
|
|||
|
|
@ -1492,6 +1492,198 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
return Ok(v);
|
||||
}
|
||||
|
||||
if name == sym::simd_masked_load {
|
||||
// simd_masked_load(mask: <N x i{M}>, pointer: *_ T, values: <N x T>) -> <N x T>
|
||||
// * N: number of elements in the input vectors
|
||||
// * T: type of the element to load
|
||||
// * M: any integer width is supported, will be truncated to i1
|
||||
// Loads contiguous elements from memory behind `pointer`, but only for
|
||||
// those lanes whose `mask` bit is enabled.
|
||||
// The memory addresses corresponding to the “off” lanes are not accessed.
|
||||
|
||||
// The element type of the "mask" argument must be a signed integer type of any width
|
||||
let mask_ty = in_ty;
|
||||
let (mask_len, mask_elem) = (in_len, in_elem);
|
||||
|
||||
// The second argument must be a pointer matching the element type
|
||||
let pointer_ty = arg_tys[1];
|
||||
|
||||
// The last argument is a passthrough vector providing values for disabled lanes
|
||||
let values_ty = arg_tys[2];
|
||||
let (values_len, values_elem) = require_simd!(values_ty, SimdThird);
|
||||
|
||||
require_simd!(ret_ty, SimdReturn);
|
||||
|
||||
// Of the same length:
|
||||
require!(
|
||||
values_len == mask_len,
|
||||
InvalidMonomorphization::ThirdArgumentLength {
|
||||
span,
|
||||
name,
|
||||
in_len: mask_len,
|
||||
in_ty: mask_ty,
|
||||
arg_ty: values_ty,
|
||||
out_len: values_len
|
||||
}
|
||||
);
|
||||
|
||||
// The return type must match the last argument type
|
||||
require!(
|
||||
ret_ty == values_ty,
|
||||
InvalidMonomorphization::ExpectedReturnType { span, name, in_ty: values_ty, ret_ty }
|
||||
);
|
||||
|
||||
require!(
|
||||
matches!(
|
||||
pointer_ty.kind(),
|
||||
ty::RawPtr(p) if p.ty == values_elem && p.ty.kind() == values_elem.kind()
|
||||
),
|
||||
InvalidMonomorphization::ExpectedElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: values_elem,
|
||||
second_arg: pointer_ty,
|
||||
in_elem: values_elem,
|
||||
in_ty: values_ty,
|
||||
mutability: ExpectedPointerMutability::Not,
|
||||
}
|
||||
);
|
||||
|
||||
require!(
|
||||
matches!(mask_elem.kind(), ty::Int(_)),
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: values_elem,
|
||||
third_arg: mask_ty,
|
||||
}
|
||||
);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
let alignment_ty = bx.type_i32();
|
||||
let alignment = bx.const_i32(bx.align_of(values_ty).bytes() as i32);
|
||||
|
||||
// Truncate the mask vector to a vector of i1s:
|
||||
let (mask, mask_ty) = {
|
||||
let i1 = bx.type_i1();
|
||||
let i1xn = bx.type_vector(i1, mask_len);
|
||||
(bx.trunc(args[0].immediate(), i1xn), i1xn)
|
||||
};
|
||||
|
||||
let llvm_pointer = bx.type_ptr();
|
||||
|
||||
// Type of the vector of elements:
|
||||
let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
|
||||
let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len);
|
||||
|
||||
let llvm_intrinsic = format!("llvm.masked.load.{llvm_elem_vec_str}.p0");
|
||||
let fn_ty = bx
|
||||
.type_func(&[llvm_pointer, alignment_ty, mask_ty, llvm_elem_vec_ty], llvm_elem_vec_ty);
|
||||
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
let v = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
&[args[1].immediate(), alignment, mask, args[2].immediate()],
|
||||
None,
|
||||
);
|
||||
return Ok(v);
|
||||
}
|
||||
|
||||
if name == sym::simd_masked_store {
|
||||
// simd_masked_store(mask: <N x i{M}>, pointer: *mut T, values: <N x T>) -> ()
|
||||
// * N: number of elements in the input vectors
|
||||
// * T: type of the element to load
|
||||
// * M: any integer width is supported, will be truncated to i1
|
||||
// Stores contiguous elements to memory behind `pointer`, but only for
|
||||
// those lanes whose `mask` bit is enabled.
|
||||
// The memory addresses corresponding to the “off” lanes are not accessed.
|
||||
|
||||
// The element type of the "mask" argument must be a signed integer type of any width
|
||||
let mask_ty = in_ty;
|
||||
let (mask_len, mask_elem) = (in_len, in_elem);
|
||||
|
||||
// The second argument must be a pointer matching the element type
|
||||
let pointer_ty = arg_tys[1];
|
||||
|
||||
// The last argument specifies the values to store to memory
|
||||
let values_ty = arg_tys[2];
|
||||
let (values_len, values_elem) = require_simd!(values_ty, SimdThird);
|
||||
|
||||
// Of the same length:
|
||||
require!(
|
||||
values_len == mask_len,
|
||||
InvalidMonomorphization::ThirdArgumentLength {
|
||||
span,
|
||||
name,
|
||||
in_len: mask_len,
|
||||
in_ty: mask_ty,
|
||||
arg_ty: values_ty,
|
||||
out_len: values_len
|
||||
}
|
||||
);
|
||||
|
||||
// The second argument must be a mutable pointer type matching the element type
|
||||
require!(
|
||||
matches!(
|
||||
pointer_ty.kind(),
|
||||
ty::RawPtr(p) if p.ty == values_elem && p.ty.kind() == values_elem.kind() && p.mutbl.is_mut()
|
||||
),
|
||||
InvalidMonomorphization::ExpectedElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: values_elem,
|
||||
second_arg: pointer_ty,
|
||||
in_elem: values_elem,
|
||||
in_ty: values_ty,
|
||||
mutability: ExpectedPointerMutability::Mut,
|
||||
}
|
||||
);
|
||||
|
||||
require!(
|
||||
matches!(mask_elem.kind(), ty::Int(_)),
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: values_elem,
|
||||
third_arg: mask_ty,
|
||||
}
|
||||
);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
let alignment_ty = bx.type_i32();
|
||||
let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32);
|
||||
|
||||
// Truncate the mask vector to a vector of i1s:
|
||||
let (mask, mask_ty) = {
|
||||
let i1 = bx.type_i1();
|
||||
let i1xn = bx.type_vector(i1, in_len);
|
||||
(bx.trunc(args[0].immediate(), i1xn), i1xn)
|
||||
};
|
||||
|
||||
let ret_t = bx.type_void();
|
||||
|
||||
let llvm_pointer = bx.type_ptr();
|
||||
|
||||
// Type of the vector of elements:
|
||||
let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
|
||||
let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len);
|
||||
|
||||
let llvm_intrinsic = format!("llvm.masked.store.{llvm_elem_vec_str}.p0");
|
||||
let fn_ty = bx.type_func(&[llvm_elem_vec_ty, llvm_pointer, alignment_ty, mask_ty], ret_t);
|
||||
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
let v = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
&[args[2].immediate(), args[1].immediate(), alignment, mask],
|
||||
None,
|
||||
);
|
||||
return Ok(v);
|
||||
}
|
||||
|
||||
if name == sym::simd_scatter {
|
||||
// simd_scatter(values: <N x T>, pointers: <N x *mut T>,
|
||||
// mask: <N x i{M}>) -> ()
|
||||
|
|
|
|||
|
|
@ -306,7 +306,9 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
}
|
||||
PrintKind::TlsModels => {
|
||||
writeln!(out, "Available TLS models:");
|
||||
for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] {
|
||||
for name in
|
||||
&["global-dynamic", "local-dynamic", "initial-exec", "local-exec", "emulated"]
|
||||
{
|
||||
writeln!(out, " {name}");
|
||||
}
|
||||
writeln!(out);
|
||||
|
|
|
|||
|
|
@ -2159,7 +2159,7 @@ extern "C" {
|
|||
SplitDwarfFile: *const c_char,
|
||||
OutputObjFile: *const c_char,
|
||||
DebugInfoCompression: *const c_char,
|
||||
ForceEmulatedTls: bool,
|
||||
UseEmulatedTls: bool,
|
||||
ArgsCstrBuff: *const c_char,
|
||||
ArgsCstrBuffLen: usize,
|
||||
) -> *mut TargetMachine;
|
||||
|
|
|
|||
|
|
@ -263,6 +263,10 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
|
|||
"sve2-bitperm",
|
||||
TargetFeatureFoldStrength::EnableOnly("neon"),
|
||||
),
|
||||
// The unaligned-scalar-mem feature was renamed to fast-unaligned-access.
|
||||
("riscv32" | "riscv64", "fast-unaligned-access") if get_version().0 <= 17 => {
|
||||
LLVMFeature::new("unaligned-scalar-mem")
|
||||
}
|
||||
(_, s) => LLVMFeature::new(s),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1748,7 +1748,9 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -
|
|||
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
|
||||
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
|
||||
if info.level.is_below_threshold(export_threshold) {
|
||||
symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
|
||||
symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
|
||||
tcx, symbol, cnum,
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_middle::ty::{self, SymbolName, TyCtxt};
|
|||
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_session::config::{CrateType, OomStrategy};
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
use rustc_target::spec::{SanitizerSet, TlsModel};
|
||||
|
||||
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
|
||||
crates_export_threshold(tcx.crate_types())
|
||||
|
|
@ -564,6 +564,12 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
|
|||
|
||||
let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
|
||||
|
||||
// thread local will not be a function call,
|
||||
// so it is safe to return before windows symbol decoration check.
|
||||
if let Some(name) = maybe_emutls_symbol_name(tcx, symbol, &undecorated) {
|
||||
return name;
|
||||
}
|
||||
|
||||
let target = &tcx.sess.target;
|
||||
if !target.is_like_windows {
|
||||
// Mach-O has a global "_" suffix and `object` crate will handle it.
|
||||
|
|
@ -624,6 +630,32 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
|
|||
format!("{prefix}{undecorated}{suffix}{args_in_bytes}")
|
||||
}
|
||||
|
||||
pub fn exporting_symbol_name_for_instance_in_crate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
symbol: ExportedSymbol<'tcx>,
|
||||
cnum: CrateNum,
|
||||
) -> String {
|
||||
let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, cnum);
|
||||
maybe_emutls_symbol_name(tcx, symbol, &undecorated).unwrap_or(undecorated)
|
||||
}
|
||||
|
||||
fn maybe_emutls_symbol_name<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
symbol: ExportedSymbol<'tcx>,
|
||||
undecorated: &str,
|
||||
) -> Option<String> {
|
||||
if matches!(tcx.sess.tls_model(), TlsModel::Emulated)
|
||||
&& let ExportedSymbol::NonGeneric(def_id) = symbol
|
||||
&& tcx.is_thread_local_static(def_id)
|
||||
{
|
||||
// When using emutls, LLVM will add the `__emutls_v.` prefix to thread local symbols,
|
||||
// and exported symbol name need to match this.
|
||||
Some(format!("__emutls_v.{undecorated}"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> {
|
||||
// Build up a map from DefId to a `NativeLib` structure, where
|
||||
// `NativeLib` internally contains information about
|
||||
|
|
|
|||
|
|
@ -566,6 +566,9 @@ fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str {
|
|||
Some(CoroutineKind::Async(CoroutineSource::Block)) => "async_block",
|
||||
Some(CoroutineKind::Async(CoroutineSource::Closure)) => "async_closure",
|
||||
Some(CoroutineKind::Async(CoroutineSource::Fn)) => "async_fn",
|
||||
Some(CoroutineKind::AsyncGen(CoroutineSource::Block)) => "async_gen_block",
|
||||
Some(CoroutineKind::AsyncGen(CoroutineSource::Closure)) => "async_gen_closure",
|
||||
Some(CoroutineKind::AsyncGen(CoroutineSource::Fn)) => "async_gen_fn",
|
||||
Some(CoroutineKind::Coroutine) => "coroutine",
|
||||
None => "closure",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let local = mir::Local::from_usize(local);
|
||||
let expected_ty = self.monomorphize(self.mir.local_decls[local].ty);
|
||||
if expected_ty != op.layout.ty {
|
||||
warn!("Unexpected initial operand type. See the issues/114858");
|
||||
warn!(
|
||||
"Unexpected initial operand type: expected {expected_ty:?}, found {:?}.\
|
||||
See <https://github.com/rust-lang/rust/issues/114858>.",
|
||||
op.layout.ty
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -291,9 +291,9 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
|||
("d", Unstable(sym::riscv_target_feature)),
|
||||
("e", Unstable(sym::riscv_target_feature)),
|
||||
("f", Unstable(sym::riscv_target_feature)),
|
||||
("fast-unaligned-access", Unstable(sym::riscv_target_feature)),
|
||||
("m", Stable),
|
||||
("relax", Unstable(sym::riscv_target_feature)),
|
||||
("unaligned-scalar-mem", Unstable(sym::riscv_target_feature)),
|
||||
("v", Unstable(sym::riscv_target_feature)),
|
||||
("zba", Stable),
|
||||
("zbb", Stable),
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use std::mem;
|
|||
use std::ops::{ControlFlow, Deref};
|
||||
|
||||
use super::ops::{self, NonConstOp, Status};
|
||||
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
|
||||
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
||||
use super::resolver::FlowSensitiveAnalysis;
|
||||
use super::{ConstCx, Qualif};
|
||||
use crate::const_eval::is_unstable_const_fn;
|
||||
|
|
@ -35,7 +35,7 @@ type QualifResults<'mir, 'tcx, Q> =
|
|||
pub struct Qualifs<'mir, 'tcx> {
|
||||
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
|
||||
needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
|
||||
// needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
|
||||
needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
||||
|
|
@ -78,27 +78,25 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
|||
local: Local,
|
||||
location: Location,
|
||||
) -> bool {
|
||||
// FIXME(effects) replace with `NeedsNonconstDrop` after const traits work again
|
||||
/*
|
||||
let ty = ccx.body.local_decls[local].ty;
|
||||
if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
|
||||
// Peeking into opaque types causes cycles if the current function declares said opaque
|
||||
// type. Thus we avoid short circuiting on the type and instead run the more expensive
|
||||
// analysis that looks at the actual usage within this function
|
||||
if !ty.has_opaque_types() && !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| {
|
||||
let ConstCx { tcx, body, .. } = *ccx;
|
||||
|
||||
FlowSensitiveAnalysis::new(NeedsDrop, ccx)
|
||||
.into_engine(tcx, &body)
|
||||
FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint()
|
||||
.into_results_cursor(&body)
|
||||
.into_results_cursor(body)
|
||||
});
|
||||
|
||||
needs_non_const_drop.seek_before_primary_effect(location);
|
||||
needs_non_const_drop.get().contains(local)
|
||||
*/
|
||||
|
||||
self.needs_drop(ccx, local, location)
|
||||
}
|
||||
|
||||
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
|
||||
|
|
@ -1013,9 +1011,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
let mut err_span = self.span;
|
||||
let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
|
||||
|
||||
// FIXME(effects) replace with `NeedsNonConstDrop` once we fix const traits
|
||||
let ty_needs_non_const_drop =
|
||||
qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place);
|
||||
qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place);
|
||||
|
||||
debug!(?ty_of_dropped_place, ?ty_needs_non_const_drop);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_span::{symbol::sym, Span};
|
|||
|
||||
use super::check::Qualifs;
|
||||
use super::ops::{self, NonConstOp};
|
||||
use super::qualifs::{NeedsDrop, Qualif};
|
||||
use super::qualifs::{NeedsNonConstDrop, Qualif};
|
||||
use super::ConstCx;
|
||||
|
||||
/// Returns `true` if we should use the more precise live drop checker that runs after drop
|
||||
|
|
@ -83,8 +83,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
|||
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
|
||||
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
|
||||
|
||||
// FIXME(effects) use `NeedsNonConstDrop`
|
||||
if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
|
||||
if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
|
||||
// Instead of throwing a bug, we just return here. This is because we have to
|
||||
// run custom `const Drop` impls.
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -23,8 +23,7 @@ pub fn in_any_value_of_ty<'tcx>(
|
|||
ConstQualifs {
|
||||
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
|
||||
needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
|
||||
// FIXME(effects)
|
||||
needs_non_const_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
|
||||
needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
|
||||
custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
|
||||
tainted_by_errors,
|
||||
}
|
||||
|
|
@ -155,12 +154,27 @@ impl Qualif for NeedsNonConstDrop {
|
|||
return false;
|
||||
}
|
||||
|
||||
// FIXME(effects) constness
|
||||
// FIXME(effects): If `destruct` is not a `const_trait`,
|
||||
// or effects are disabled in this crate, then give up.
|
||||
let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
|
||||
if cx.tcx.generics_of(destruct_def_id).host_effect_index.is_none()
|
||||
|| !cx.tcx.features().effects
|
||||
{
|
||||
return NeedsDrop::in_any_value_of_ty(cx, ty);
|
||||
}
|
||||
|
||||
let obligation = Obligation::new(
|
||||
cx.tcx,
|
||||
ObligationCause::dummy_with_span(cx.body.span),
|
||||
cx.param_env,
|
||||
ty::TraitRef::from_lang_item(cx.tcx, LangItem::Destruct, cx.body.span, [ty]),
|
||||
ty::TraitRef::new(
|
||||
cx.tcx,
|
||||
destruct_def_id,
|
||||
[
|
||||
ty::GenericArg::from(ty),
|
||||
ty::GenericArg::from(cx.tcx.expected_const_effect_param_for_body(cx.def_id())),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
let infcx = cx.tcx.infer_ctxt().build();
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ fn default_client() -> Client {
|
|||
|
||||
static GLOBAL_CLIENT_CHECKED: OnceLock<Client> = OnceLock::new();
|
||||
|
||||
pub fn check(report_warning: impl FnOnce(&'static str)) {
|
||||
pub fn initialize_checked(report_warning: impl FnOnce(&'static str)) {
|
||||
let client_checked = match &*GLOBAL_CLIENT {
|
||||
Ok(client) => client.clone(),
|
||||
Err(e) => {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ rustc_mir_transform = { path = "../rustc_mir_transform" }
|
|||
rustc_monomorphize = { path = "../rustc_monomorphize" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_passes = { path = "../rustc_passes" }
|
||||
rustc_pattern_analysis = { path = "../rustc_pattern_analysis" }
|
||||
rustc_privacy = { path = "../rustc_privacy" }
|
||||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc_resolve = { path = "../rustc_resolve" }
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
|
|||
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_parse::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_passes::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_pattern_analysis::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_privacy::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_query_system::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_resolve::DEFAULT_LOCALE_RESOURCE,
|
||||
|
|
|
|||
|
|
@ -591,17 +591,18 @@ impl Diagnostic {
|
|||
pub fn multipart_suggestion_with_style(
|
||||
&mut self,
|
||||
msg: impl Into<SubdiagnosticMessage>,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
mut suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
style: SuggestionStyle,
|
||||
) -> &mut Self {
|
||||
let mut parts = suggestion
|
||||
suggestion.sort_unstable();
|
||||
suggestion.dedup();
|
||||
|
||||
let parts = suggestion
|
||||
.into_iter()
|
||||
.map(|(span, snippet)| SubstitutionPart { snippet, span })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
parts.sort_unstable_by_key(|part| part.span);
|
||||
|
||||
assert!(!parts.is_empty());
|
||||
debug_assert_eq!(
|
||||
parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ expand_macro_const_stability =
|
|||
.label = invalid const stability attribute
|
||||
.label2 = const stability attribute affects this macro
|
||||
|
||||
expand_macro_expands_to_match_arm = macros cannot expand to match arms
|
||||
|
||||
expand_malformed_feature_attribute =
|
||||
malformed `feature` attribute input
|
||||
.expected = expected just one word
|
||||
|
|
|
|||
|
|
@ -505,7 +505,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
attrs: AttrVec::new(),
|
||||
pat,
|
||||
guard: None,
|
||||
body: expr,
|
||||
body: Some(expr),
|
||||
span,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
|
|
@ -547,7 +547,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
binder: ast::ClosureBinder::NotPresent,
|
||||
capture_clause: ast::CaptureBy::Ref,
|
||||
constness: ast::Const::No,
|
||||
coro_kind: None,
|
||||
coroutine_kind: None,
|
||||
movability: ast::Movability::Movable,
|
||||
fn_decl,
|
||||
body,
|
||||
|
|
|
|||
|
|
@ -304,6 +304,8 @@ pub(crate) struct IncompleteParse<'a> {
|
|||
pub label_span: Span,
|
||||
pub macro_path: &'a ast::Path,
|
||||
pub kind_name: &'a str,
|
||||
#[note(expand_macro_expands_to_match_arm)]
|
||||
pub expands_to_match_arm: Option<()>,
|
||||
|
||||
#[suggestion(
|
||||
expand_suggestion_add_semi,
|
||||
|
|
|
|||
|
|
@ -955,12 +955,15 @@ pub fn ensure_complete_parse<'a>(
|
|||
_ => None,
|
||||
};
|
||||
|
||||
let expands_to_match_arm = kind_name == "pattern" && parser.token == token::FatArrow;
|
||||
|
||||
parser.sess.emit_err(IncompleteParse {
|
||||
span: def_site_span,
|
||||
token,
|
||||
label_span: span,
|
||||
macro_path,
|
||||
kind_name,
|
||||
expands_to_match_arm: expands_to_match_arm.then_some(()),
|
||||
add_semicolon,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ pub fn placeholder(
|
|||
}]),
|
||||
AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
|
||||
attrs: Default::default(),
|
||||
body: expr_placeholder(),
|
||||
body: Some(expr_placeholder()),
|
||||
guard: None,
|
||||
id,
|
||||
pat: pat(),
|
||||
|
|
|
|||
|
|
@ -1056,6 +1056,23 @@ impl<'hir> Pat<'hir> {
|
|||
true
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether this a never pattern.
|
||||
pub fn is_never_pattern(&self) -> bool {
|
||||
let mut is_never_pattern = false;
|
||||
self.walk(|pat| match &pat.kind {
|
||||
PatKind::Never => {
|
||||
is_never_pattern = true;
|
||||
false
|
||||
}
|
||||
PatKind::Or(s) => {
|
||||
is_never_pattern = s.iter().all(|p| p.is_never_pattern());
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
});
|
||||
is_never_pattern
|
||||
}
|
||||
}
|
||||
|
||||
/// A single field in a struct pattern.
|
||||
|
|
@ -1339,12 +1356,16 @@ impl<'hir> Body<'hir> {
|
|||
/// The type of source expression that caused this coroutine to be created.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum CoroutineKind {
|
||||
/// An explicit `async` block or the body of an async function.
|
||||
/// An explicit `async` block or the body of an `async` function.
|
||||
Async(CoroutineSource),
|
||||
|
||||
/// An explicit `gen` block or the body of a `gen` function.
|
||||
Gen(CoroutineSource),
|
||||
|
||||
/// An explicit `async gen` block or the body of an `async gen` function,
|
||||
/// which is able to both `yield` and `.await`.
|
||||
AsyncGen(CoroutineSource),
|
||||
|
||||
/// A coroutine literal created via a `yield` inside a closure.
|
||||
Coroutine,
|
||||
}
|
||||
|
|
@ -1369,6 +1390,14 @@ impl fmt::Display for CoroutineKind {
|
|||
}
|
||||
k.fmt(f)
|
||||
}
|
||||
CoroutineKind::AsyncGen(k) => {
|
||||
if f.alternate() {
|
||||
f.write_str("`async gen` ")?;
|
||||
} else {
|
||||
f.write_str("async gen ")?
|
||||
}
|
||||
k.fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2064,17 +2093,6 @@ impl fmt::Display for YieldSource {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<CoroutineKind> for YieldSource {
|
||||
fn from(kind: CoroutineKind) -> Self {
|
||||
match kind {
|
||||
// Guess based on the kind of the current coroutine.
|
||||
CoroutineKind::Coroutine => Self::Yield,
|
||||
CoroutineKind::Async(_) => Self::Await { expr: None },
|
||||
CoroutineKind::Gen(_) => Self::Yield,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// N.B., if you change this, you'll probably want to change the corresponding
|
||||
// type structure in middle/ty.rs as well.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
|
|
@ -2254,11 +2272,6 @@ pub enum ImplItemKind<'hir> {
|
|||
Type(&'hir Ty<'hir>),
|
||||
}
|
||||
|
||||
/// The name of the associated type for `Fn` return types.
|
||||
pub const FN_OUTPUT_NAME: Symbol = sym::Output;
|
||||
/// The name of the associated type for `Iterator` item types.
|
||||
pub const ITERATOR_ITEM_NAME: Symbol = sym::Item;
|
||||
|
||||
/// Bind a type to an associated type (i.e., `A = Foo`).
|
||||
///
|
||||
/// Bindings like `A: Debug` are represented as a special type `A =
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ language_item_table! {
|
|||
|
||||
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None;
|
||||
Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Minimum(1);
|
||||
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
|
||||
|
|
@ -294,6 +295,10 @@ language_item_table! {
|
|||
PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
|
||||
PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None;
|
||||
|
||||
AsyncGenReady, sym::AsyncGenReady, async_gen_ready, Target::Method(MethodKind::Inherent), GenericRequirement::Exact(1);
|
||||
AsyncGenPending, sym::AsyncGenPending, async_gen_pending, Target::AssocConst, GenericRequirement::Exact(1);
|
||||
AsyncGenFinished, sym::AsyncGenFinished, async_gen_finished, Target::AssocConst, GenericRequirement::Exact(1);
|
||||
|
||||
// FIXME(swatinem): the following lang items are used for async lowering and
|
||||
// should become obsolete eventually.
|
||||
ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,28 @@
|
|||
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$ty_param_name}`
|
||||
.label = ambiguous associated {$assoc_kind} `{$assoc_name}`
|
||||
|
||||
hir_analysis_ambiguous_lifetime_bound =
|
||||
ambiguous lifetime bound, explicit lifetime bound required
|
||||
|
||||
hir_analysis_assoc_bound_on_const = expected associated type, found {$descr}
|
||||
.note = trait bounds not allowed on {$descr}
|
||||
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}`
|
||||
|
||||
hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named ->
|
||||
[true] an
|
||||
*[false] a similarly named
|
||||
} associated {$assoc_kind} `{$suggested_name}` in the trait `{$trait_name}`
|
||||
hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_name}` not found
|
||||
hir_analysis_assoc_item_not_found_other_sugg = `{$ty_param_name}` has the following associated {$assoc_kind}
|
||||
hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg = change the associated {$assoc_kind} name to use `{$suggested_name}` from `{$trait_name}`
|
||||
hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = and also change the associated {$assoc_kind} name
|
||||
hir_analysis_assoc_item_not_found_similar_sugg = there is an associated {$assoc_kind} with a similar name
|
||||
|
||||
hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got}
|
||||
.label = unexpected {$got}
|
||||
.expected_because_label = expected a {$expected} because of this associated {$expected}
|
||||
.note = the associated {$assoc_kind} is defined here
|
||||
.bound_on_assoc_const_label = bounds are not allowed on associated constants
|
||||
|
||||
hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here
|
||||
|
||||
hir_analysis_assoc_type_binding_not_allowed =
|
||||
associated type bindings are not allowed here
|
||||
|
|
@ -280,10 +300,6 @@ hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is no
|
|||
|
||||
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
|
||||
|
||||
hir_analysis_return_type_notation_conflicting_bound =
|
||||
ambiguous associated function `{$assoc_name}` for `{$ty_name}`
|
||||
.note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}`
|
||||
|
||||
hir_analysis_return_type_notation_equality_bound =
|
||||
return type notation is not allowed to use type equality
|
||||
|
||||
|
|
@ -294,9 +310,6 @@ hir_analysis_return_type_notation_illegal_param_type =
|
|||
return type notation is not allowed for functions that have type parameters
|
||||
.label = type parameter declared here
|
||||
|
||||
hir_analysis_return_type_notation_missing_method =
|
||||
cannot find associated function `{$assoc_name}` for `{$ty_name}`
|
||||
|
||||
hir_analysis_return_type_notation_on_non_rpitit =
|
||||
return type notation used on function that is not `async` and does not return `impl Trait`
|
||||
.note = function returns `{$ty}`, which is not compatible with associated type return bounds
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ use rustc_errors::struct_span_err;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_lint_defs::Applicability;
|
||||
use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self as ty, Ty};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_trait_selection::traits;
|
||||
|
|
@ -256,64 +255,49 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
|
||||
let tcx = self.tcx();
|
||||
|
||||
let return_type_notation =
|
||||
binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
|
||||
|
||||
let candidate = if return_type_notation {
|
||||
if self.trait_defines_associated_item_named(
|
||||
trait_ref.def_id(),
|
||||
ty::AssocKind::Fn,
|
||||
binding.item_name,
|
||||
) {
|
||||
trait_ref
|
||||
let assoc_kind =
|
||||
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
|
||||
ty::AssocKind::Fn
|
||||
} else if let ConvertedBindingKind::Equality(term) = binding.kind
|
||||
&& let ty::TermKind::Const(_) = term.node.unpack()
|
||||
{
|
||||
ty::AssocKind::Const
|
||||
} else {
|
||||
self.one_bound_for_assoc_method(
|
||||
traits::supertraits(tcx, trait_ref),
|
||||
trait_ref.print_only_trait_path(),
|
||||
binding.item_name,
|
||||
path_span,
|
||||
)?
|
||||
}
|
||||
} else if self.trait_defines_associated_item_named(
|
||||
ty::AssocKind::Type
|
||||
};
|
||||
|
||||
let candidate = if self.trait_defines_associated_item_named(
|
||||
trait_ref.def_id(),
|
||||
ty::AssocKind::Type,
|
||||
assoc_kind,
|
||||
binding.item_name,
|
||||
) {
|
||||
// Simple case: X is defined in the current trait.
|
||||
// Simple case: The assoc item is defined in the current trait.
|
||||
trait_ref
|
||||
} else {
|
||||
// Otherwise, we have to walk through the supertraits to find
|
||||
// those that do.
|
||||
self.one_bound_for_assoc_type(
|
||||
// one that does define it.
|
||||
self.one_bound_for_assoc_item(
|
||||
|| traits::supertraits(tcx, trait_ref),
|
||||
trait_ref.skip_binder().print_only_trait_name(),
|
||||
None,
|
||||
assoc_kind,
|
||||
binding.item_name,
|
||||
path_span,
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(term) => Some(term),
|
||||
_ => None,
|
||||
},
|
||||
Some(&binding),
|
||||
)?
|
||||
};
|
||||
|
||||
let (assoc_ident, def_scope) =
|
||||
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
|
||||
|
||||
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
|
||||
// of calling `filter_by_name_and_kind`.
|
||||
let find_item_of_kind = |kind| {
|
||||
tcx.associated_items(candidate.def_id())
|
||||
.filter_by_name_unhygienic(assoc_ident.name)
|
||||
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
|
||||
};
|
||||
let assoc_item = if return_type_notation {
|
||||
find_item_of_kind(ty::AssocKind::Fn)
|
||||
} else {
|
||||
find_item_of_kind(ty::AssocKind::Type)
|
||||
.or_else(|| find_item_of_kind(ty::AssocKind::Const))
|
||||
}
|
||||
.expect("missing associated type");
|
||||
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
|
||||
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
|
||||
// `assoc_ident` again and again.
|
||||
let assoc_item = tcx
|
||||
.associated_items(candidate.def_id())
|
||||
.filter_by_name_unhygienic(assoc_ident.name)
|
||||
.find(|i| i.kind == assoc_kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
|
||||
.expect("missing associated item");
|
||||
|
||||
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
|
||||
tcx.sess
|
||||
|
|
@ -340,7 +324,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
.or_insert(binding.span);
|
||||
}
|
||||
|
||||
let projection_ty = if return_type_notation {
|
||||
let projection_ty = if let ty::AssocKind::Fn = assoc_kind {
|
||||
let mut emitted_bad_param_err = false;
|
||||
// If we have an method return type bound, then we need to substitute
|
||||
// the method's early bound params with suitable late-bound params.
|
||||
|
|
@ -467,7 +451,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
let late_bound_in_trait_ref =
|
||||
tcx.collect_constrained_late_bound_regions(&projection_ty);
|
||||
let late_bound_in_ty =
|
||||
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
|
||||
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty.node));
|
||||
debug!(?late_bound_in_trait_ref);
|
||||
debug!(?late_bound_in_ty);
|
||||
|
||||
|
|
@ -492,77 +476,27 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
let assoc_item_def_id = projection_ty.skip_binder().def_id;
|
||||
let def_kind = tcx.def_kind(assoc_item_def_id);
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(..) if return_type_notation => {
|
||||
ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => {
|
||||
return Err(self.tcx().sess.emit_err(
|
||||
crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
|
||||
));
|
||||
}
|
||||
ConvertedBindingKind::Equality(mut term) => {
|
||||
ConvertedBindingKind::Equality(term) => {
|
||||
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
||||
// the "projection predicate" for:
|
||||
//
|
||||
// `<T as Iterator>::Item = u32`
|
||||
match (def_kind, term.unpack()) {
|
||||
(DefKind::AssocTy, ty::TermKind::Ty(_))
|
||||
| (DefKind::AssocConst, ty::TermKind::Const(_)) => (),
|
||||
(_, _) => {
|
||||
let got = if let Some(_) = term.ty() { "type" } else { "constant" };
|
||||
let expected = tcx.def_descr(assoc_item_def_id);
|
||||
let mut err = tcx.sess.struct_span_err(
|
||||
binding.span,
|
||||
format!("expected {expected} bound, found {got}"),
|
||||
);
|
||||
err.span_note(
|
||||
tcx.def_span(assoc_item_def_id),
|
||||
format!("{expected} defined here"),
|
||||
);
|
||||
|
||||
if let DefKind::AssocConst = def_kind
|
||||
&& let Some(t) = term.ty()
|
||||
&& (t.is_enum() || t.references_error())
|
||||
&& tcx.features().associated_const_equality
|
||||
{
|
||||
err.span_suggestion(
|
||||
binding.span,
|
||||
"if equating a const, try wrapping with braces",
|
||||
format!("{} = {{ const }}", binding.item_name),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
let reported = err.emit();
|
||||
term = match def_kind {
|
||||
DefKind::AssocTy => Ty::new_error(tcx, reported).into(),
|
||||
DefKind::AssocConst => ty::Const::new_error(
|
||||
tcx,
|
||||
reported,
|
||||
tcx.type_of(assoc_item_def_id)
|
||||
.instantiate(tcx, projection_ty.skip_binder().args),
|
||||
)
|
||||
.into(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
}
|
||||
bounds.push_projection_bound(
|
||||
tcx,
|
||||
projection_ty
|
||||
.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
|
||||
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
|
||||
projection_ty,
|
||||
term: term.node,
|
||||
}),
|
||||
binding.span,
|
||||
);
|
||||
}
|
||||
ConvertedBindingKind::Constraint(ast_bounds) => {
|
||||
match def_kind {
|
||||
DefKind::AssocTy => {}
|
||||
_ => {
|
||||
return Err(tcx.sess.emit_err(errors::AssocBoundOnConst {
|
||||
span: assoc_ident.span,
|
||||
descr: tcx.def_descr(assoc_item_def_id),
|
||||
}));
|
||||
}
|
||||
}
|
||||
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
|
||||
//
|
||||
// `<T as Iterator>::Item: Debug`
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
use crate::astconv::AstConv;
|
||||
use crate::astconv::{AstConv, ConvertedBindingKind};
|
||||
use crate::errors::{
|
||||
AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
||||
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
||||
ParenthesizedFnTraitExpansion,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::traits::error_reporting::report_object_safety_error;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_infer::traits::FulfillmentError;
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, AssocItem, AssocKind, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
|
|
@ -97,83 +98,88 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn complain_about_assoc_type_not_found<I>(
|
||||
pub(super) fn complain_about_assoc_item_not_found<I>(
|
||||
&self,
|
||||
all_candidates: impl Fn() -> I,
|
||||
ty_param_name: &str,
|
||||
ty_param_def_id: Option<LocalDefId>,
|
||||
assoc_kind: ty::AssocKind,
|
||||
assoc_name: Ident,
|
||||
span: Span,
|
||||
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
|
||||
) -> ErrorGuaranteed
|
||||
where
|
||||
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
// First and foremost, provide a more user-friendly & “intuitive” error on kind mismatches.
|
||||
if let Some(assoc_item) = all_candidates().find_map(|r| {
|
||||
tcx.associated_items(r.def_id())
|
||||
.filter_by_name_unhygienic(assoc_name.name)
|
||||
.find(|item| tcx.hygienic_eq(assoc_name, item.ident(tcx), r.def_id()))
|
||||
}) {
|
||||
return self.complain_about_assoc_kind_mismatch(
|
||||
assoc_item, assoc_kind, assoc_name, span, binding,
|
||||
);
|
||||
}
|
||||
|
||||
let assoc_kind_str = super::assoc_kind_str(assoc_kind);
|
||||
|
||||
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
|
||||
// valid span, so we point at the whole path segment instead.
|
||||
let is_dummy = assoc_name.span == DUMMY_SP;
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx().sess,
|
||||
if is_dummy { span } else { assoc_name.span },
|
||||
E0220,
|
||||
"associated type `{}` not found for `{}`",
|
||||
let mut err = errors::AssocItemNotFound {
|
||||
span: if is_dummy { span } else { assoc_name.span },
|
||||
assoc_name,
|
||||
ty_param_name
|
||||
);
|
||||
assoc_kind: assoc_kind_str,
|
||||
ty_param_name,
|
||||
label: None,
|
||||
sugg: None,
|
||||
};
|
||||
|
||||
if is_dummy {
|
||||
err.span_label(span, format!("associated type `{assoc_name}` not found"));
|
||||
return err.emit();
|
||||
err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
|
||||
return tcx.sess.emit_err(err);
|
||||
}
|
||||
|
||||
let all_candidate_names: Vec<_> = all_candidates()
|
||||
.flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
|
||||
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
|
||||
.filter_map(|item| {
|
||||
if !item.is_impl_trait_in_trait() && item.kind == ty::AssocKind::Type {
|
||||
Some(item.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Some(suggested_name) =
|
||||
find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
|
||||
{
|
||||
err.span_suggestion(
|
||||
assoc_name.span,
|
||||
"there is an associated type with a similar name",
|
||||
err.sugg = Some(errors::AssocItemNotFoundSugg::Similar {
|
||||
span: assoc_name.span,
|
||||
assoc_kind: assoc_kind_str,
|
||||
suggested_name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return err.emit();
|
||||
});
|
||||
return tcx.sess.emit_err(err);
|
||||
}
|
||||
|
||||
// If we didn't find a good item in the supertraits (or couldn't get
|
||||
// the supertraits), like in ItemCtxt, then look more generally from
|
||||
// all visible traits. If there's one clear winner, just suggest that.
|
||||
|
||||
let visible_traits: Vec<_> = self
|
||||
.tcx()
|
||||
let visible_traits: Vec<_> = tcx
|
||||
.all_traits()
|
||||
.filter(|trait_def_id| {
|
||||
let viz = self.tcx().visibility(*trait_def_id);
|
||||
let viz = tcx.visibility(*trait_def_id);
|
||||
let def_id = self.item_def_id();
|
||||
viz.is_accessible_from(def_id, self.tcx())
|
||||
viz.is_accessible_from(def_id, tcx)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let wider_candidate_names: Vec<_> = visible_traits
|
||||
.iter()
|
||||
.flat_map(|trait_def_id| {
|
||||
self.tcx().associated_items(*trait_def_id).in_definition_order()
|
||||
})
|
||||
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
|
||||
.filter_map(|item| {
|
||||
if !item.is_impl_trait_in_trait() && item.kind == ty::AssocKind::Type {
|
||||
Some(item.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -182,52 +188,51 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
{
|
||||
if let [best_trait] = visible_traits
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|trait_def_id| {
|
||||
self.tcx()
|
||||
.associated_items(*trait_def_id)
|
||||
tcx.associated_items(trait_def_id)
|
||||
.filter_by_name_unhygienic(suggested_name)
|
||||
.any(|item| item.kind == ty::AssocKind::Type)
|
||||
.any(|item| item.kind == assoc_kind)
|
||||
})
|
||||
.collect::<Vec<_>>()[..]
|
||||
{
|
||||
let trait_name = self.tcx().def_path_str(*best_trait);
|
||||
let an = if suggested_name != assoc_name.name { "a similarly named" } else { "an" };
|
||||
err.span_label(
|
||||
assoc_name.span,
|
||||
format!(
|
||||
"there is {an} associated type `{suggested_name}` in the \
|
||||
trait `{trait_name}`",
|
||||
),
|
||||
);
|
||||
let hir = self.tcx().hir();
|
||||
let trait_name = tcx.def_path_str(best_trait);
|
||||
err.label = Some(errors::AssocItemNotFoundLabel::FoundInOtherTrait {
|
||||
span: assoc_name.span,
|
||||
assoc_kind: assoc_kind_str,
|
||||
trait_name: &trait_name,
|
||||
suggested_name,
|
||||
identically_named: suggested_name == assoc_name.name,
|
||||
});
|
||||
let hir = tcx.hir();
|
||||
if let Some(def_id) = ty_param_def_id
|
||||
&& let parent = hir.get_parent_item(self.tcx().local_def_id_to_hir_id(def_id))
|
||||
&& let parent = hir.get_parent_item(tcx.local_def_id_to_hir_id(def_id))
|
||||
&& let Some(generics) = hir.get_generics(parent.def_id)
|
||||
{
|
||||
if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any(
|
||||
|b| match b {
|
||||
hir::GenericBound::Trait(t, ..) => {
|
||||
t.trait_ref.trait_def_id().as_ref() == Some(best_trait)
|
||||
t.trait_ref.trait_def_id() == Some(best_trait)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
) {
|
||||
// The type param already has a bound for `trait_name`, we just need to
|
||||
// change the associated type.
|
||||
err.span_suggestion_verbose(
|
||||
assoc_name.span,
|
||||
format!(
|
||||
"change the associated type name to use `{suggested_name}` from \
|
||||
`{trait_name}`",
|
||||
),
|
||||
suggested_name.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if suggest_constraining_type_param(
|
||||
self.tcx(),
|
||||
// change the associated item.
|
||||
err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
|
||||
span: assoc_name.span,
|
||||
assoc_kind: assoc_kind_str,
|
||||
suggested_name,
|
||||
});
|
||||
return tcx.sess.emit_err(err);
|
||||
}
|
||||
|
||||
let mut err = tcx.sess.create_err(err);
|
||||
if suggest_constraining_type_param(
|
||||
tcx,
|
||||
generics,
|
||||
&mut err,
|
||||
ty_param_name,
|
||||
&ty_param_name,
|
||||
&trait_name,
|
||||
None,
|
||||
None,
|
||||
|
|
@ -237,39 +242,101 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
// was also not an exact match, so we also suggest changing it.
|
||||
err.span_suggestion_verbose(
|
||||
assoc_name.span,
|
||||
"and also change the associated type name",
|
||||
fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg,
|
||||
suggested_name.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
return err.emit();
|
||||
}
|
||||
return err.emit();
|
||||
return tcx.sess.emit_err(err);
|
||||
}
|
||||
}
|
||||
|
||||
// If we still couldn't find any associated type, and only one associated type exists,
|
||||
// suggests using it.
|
||||
|
||||
if all_candidate_names.len() == 1 {
|
||||
if let [candidate_name] = all_candidate_names.as_slice() {
|
||||
// this should still compile, except on `#![feature(associated_type_defaults)]`
|
||||
// where it could suggests `type A = Self::A`, thus recursing infinitely
|
||||
let applicability = if self.tcx().features().associated_type_defaults {
|
||||
let applicability = if tcx.features().associated_type_defaults {
|
||||
Applicability::Unspecified
|
||||
} else {
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
|
||||
err.span_suggestion(
|
||||
assoc_name.span,
|
||||
format!("`{ty_param_name}` has the following associated type"),
|
||||
all_candidate_names.first().unwrap().to_string(),
|
||||
err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
|
||||
span: assoc_name.span,
|
||||
applicability,
|
||||
);
|
||||
ty_param_name,
|
||||
assoc_kind: assoc_kind_str,
|
||||
suggested_name: *candidate_name,
|
||||
});
|
||||
} else {
|
||||
err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found"));
|
||||
err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span });
|
||||
}
|
||||
|
||||
err.emit()
|
||||
tcx.sess.emit_err(err)
|
||||
}
|
||||
|
||||
fn complain_about_assoc_kind_mismatch(
|
||||
&self,
|
||||
assoc_item: &ty::AssocItem,
|
||||
assoc_kind: ty::AssocKind,
|
||||
ident: Ident,
|
||||
span: Span,
|
||||
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
|
||||
) -> ErrorGuaranteed {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
|
||||
&& let Some(binding) = binding
|
||||
&& let ConvertedBindingKind::Constraint(_) = binding.kind
|
||||
{
|
||||
let lo = if binding.gen_args.span_ext.is_dummy() {
|
||||
ident.span
|
||||
} else {
|
||||
binding.gen_args.span_ext
|
||||
};
|
||||
Some(lo.between(span.shrink_to_hi()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// FIXME(associated_const_equality): This has quite a few false positives and negatives.
|
||||
let wrap_in_braces_sugg = if let Some(binding) = binding
|
||||
&& let ConvertedBindingKind::Equality(term) = binding.kind
|
||||
&& let ty::TermKind::Ty(ty) = term.node.unpack()
|
||||
&& (ty.is_enum() || ty.references_error())
|
||||
&& tcx.features().associated_const_equality
|
||||
{
|
||||
Some(errors::AssocKindMismatchWrapInBracesSugg {
|
||||
lo: term.span.shrink_to_lo(),
|
||||
hi: term.span.shrink_to_hi(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since
|
||||
// one can argue that that's more “untuitive” to the user.
|
||||
let (span, expected_because_label, expected, got) = if let Some(binding) = binding
|
||||
&& let ConvertedBindingKind::Equality(term) = binding.kind
|
||||
{
|
||||
(term.span, Some(ident.span), assoc_item.kind, assoc_kind)
|
||||
} else {
|
||||
(ident.span, None, assoc_kind, assoc_item.kind)
|
||||
};
|
||||
|
||||
tcx.sess.emit_err(errors::AssocKindMismatch {
|
||||
span,
|
||||
expected: super::assoc_kind_str(expected),
|
||||
got: super::assoc_kind_str(got),
|
||||
expected_because_label,
|
||||
assoc_kind: super::assoc_kind_str(assoc_item.kind),
|
||||
def_span: tcx.def_span(assoc_item.def_id),
|
||||
bound_on_assoc_const_label,
|
||||
wrap_in_braces_sugg,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn complain_about_ambiguous_inherent_assoc_type(
|
||||
|
|
@ -598,7 +665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind(
|
||||
tcx,
|
||||
ident,
|
||||
AssocKind::Type,
|
||||
ty::AssocKind::Type,
|
||||
trait_def,
|
||||
);
|
||||
|
||||
|
|
@ -606,7 +673,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}))
|
||||
})
|
||||
.flatten()
|
||||
.collect::<FxHashMap<Symbol, &AssocItem>>();
|
||||
.collect::<FxHashMap<Symbol, &ty::AssocItem>>();
|
||||
|
||||
let mut names = names
|
||||
.into_iter()
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ use crate::require_c_abi_if_c_variadic;
|
|||
use rustc_ast::TraitObjectSyntax;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{
|
||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
|
||||
MultiSpan,
|
||||
error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
FatalError, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
||||
|
|
@ -36,6 +36,7 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
|
|
@ -162,7 +163,7 @@ struct ConvertedBinding<'a, 'tcx> {
|
|||
|
||||
#[derive(Debug)]
|
||||
enum ConvertedBindingKind<'a, 'tcx> {
|
||||
Equality(ty::Term<'tcx>),
|
||||
Equality(Spanned<ty::Term<'tcx>>),
|
||||
Constraint(&'a [hir::GenericBound<'a>]),
|
||||
}
|
||||
|
||||
|
|
@ -595,12 +596,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.map(|binding| {
|
||||
let kind = match &binding.kind {
|
||||
hir::TypeBindingKind::Equality { term } => match term {
|
||||
hir::Term::Ty(ty) => {
|
||||
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
|
||||
}
|
||||
hir::Term::Ty(ty) => ConvertedBindingKind::Equality(respan(
|
||||
ty.span,
|
||||
self.ast_ty_to_ty(ty).into(),
|
||||
)),
|
||||
hir::Term::Const(c) => {
|
||||
let span = self.tcx().def_span(c.def_id);
|
||||
let c = Const::from_anon_const(self.tcx(), c.def_id);
|
||||
ConvertedBindingKind::Equality(c.into())
|
||||
ConvertedBindingKind::Equality(respan(span, c.into()))
|
||||
}
|
||||
},
|
||||
hir::TypeBindingKind::Constraint { bounds } => {
|
||||
|
|
@ -1056,7 +1059,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
|
||||
|
||||
let param_name = tcx.hir().ty_param_name(ty_param_def_id);
|
||||
self.one_bound_for_assoc_type(
|
||||
self.one_bound_for_assoc_item(
|
||||
|| {
|
||||
traits::transitive_bounds_that_define_assoc_item(
|
||||
tcx,
|
||||
|
|
@ -1068,6 +1071,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
},
|
||||
param_name,
|
||||
Some(ty_param_def_id),
|
||||
ty::AssocKind::Type,
|
||||
assoc_name,
|
||||
span,
|
||||
None,
|
||||
|
|
@ -1076,48 +1080,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
// Checks that `bounds` contains exactly one element and reports appropriate
|
||||
// errors otherwise.
|
||||
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
|
||||
fn one_bound_for_assoc_type<I>(
|
||||
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, binding), ret)]
|
||||
fn one_bound_for_assoc_item<I>(
|
||||
&self,
|
||||
all_candidates: impl Fn() -> I,
|
||||
ty_param_name: impl Display,
|
||||
ty_param_def_id: Option<LocalDefId>,
|
||||
assoc_kind: ty::AssocKind,
|
||||
assoc_name: Ident,
|
||||
span: Span,
|
||||
is_equality: Option<ty::Term<'tcx>>,
|
||||
binding: Option<&ConvertedBinding<'_, 'tcx>>,
|
||||
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
|
||||
where
|
||||
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
let mut matching_candidates = all_candidates().filter(|r| {
|
||||
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Type, assoc_name)
|
||||
});
|
||||
let mut const_candidates = all_candidates().filter(|r| {
|
||||
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
|
||||
self.trait_defines_associated_item_named(r.def_id(), assoc_kind, assoc_name)
|
||||
});
|
||||
|
||||
let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next())
|
||||
{
|
||||
(Some(bound), _) => (bound, matching_candidates.next()),
|
||||
(None, Some(bound)) => (bound, const_candidates.next()),
|
||||
(None, None) => {
|
||||
let reported = self.complain_about_assoc_type_not_found(
|
||||
all_candidates,
|
||||
&ty_param_name.to_string(),
|
||||
ty_param_def_id,
|
||||
assoc_name,
|
||||
span,
|
||||
);
|
||||
return Err(reported);
|
||||
}
|
||||
let Some(mut bound) = matching_candidates.next() else {
|
||||
let reported = self.complain_about_assoc_item_not_found(
|
||||
all_candidates,
|
||||
&ty_param_name.to_string(),
|
||||
ty_param_def_id,
|
||||
assoc_kind,
|
||||
assoc_name,
|
||||
span,
|
||||
binding,
|
||||
);
|
||||
return Err(reported);
|
||||
};
|
||||
debug!(?bound);
|
||||
|
||||
// look for a candidate that is not the same as our first bound, disregarding
|
||||
// whether the bound is const.
|
||||
let mut next_cand = matching_candidates.next();
|
||||
while let Some(mut bound2) = next_cand {
|
||||
debug!(?bound2);
|
||||
let tcx = self.tcx();
|
||||
if bound2.bound_vars() != bound.bound_vars() {
|
||||
break;
|
||||
}
|
||||
|
|
@ -1138,7 +1139,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg });
|
||||
|
||||
if unconsted_args.eq(bound2.skip_binder().args.iter()) {
|
||||
next_cand = matching_candidates.next().or_else(|| const_candidates.next());
|
||||
next_cand = matching_candidates.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
@ -1147,48 +1148,53 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
if let Some(bound2) = next_cand {
|
||||
debug!(?bound2);
|
||||
|
||||
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
|
||||
let mut err = if is_equality.is_some() {
|
||||
// More specific Error Index entry.
|
||||
struct_span_err!(
|
||||
self.tcx().sess,
|
||||
span,
|
||||
E0222,
|
||||
"ambiguous associated type `{}` in bounds of `{}`",
|
||||
assoc_name,
|
||||
ty_param_name
|
||||
)
|
||||
} else {
|
||||
struct_span_err!(
|
||||
self.tcx().sess,
|
||||
span,
|
||||
E0221,
|
||||
"ambiguous associated type `{}` in bounds of `{}`",
|
||||
assoc_name,
|
||||
ty_param_name
|
||||
)
|
||||
};
|
||||
err.span_label(span, format!("ambiguous associated type `{assoc_name}`"));
|
||||
let assoc_kind_str = assoc_kind_str(assoc_kind);
|
||||
let ty_param_name = &ty_param_name.to_string();
|
||||
let mut err = tcx.sess.create_err(crate::errors::AmbiguousAssocItem {
|
||||
span,
|
||||
assoc_kind: assoc_kind_str,
|
||||
assoc_name,
|
||||
ty_param_name,
|
||||
});
|
||||
// Provide a more specific error code index entry for equality bindings.
|
||||
err.code(
|
||||
if let Some(binding) = binding
|
||||
&& let ConvertedBindingKind::Equality(_) = binding.kind
|
||||
{
|
||||
error_code!(E0222)
|
||||
} else {
|
||||
error_code!(E0221)
|
||||
},
|
||||
);
|
||||
|
||||
// FIXME(#97583): Resugar equality bounds to type/const bindings.
|
||||
// FIXME: Turn this into a structured, translateable & more actionable suggestion.
|
||||
let mut where_bounds = vec![];
|
||||
for bound in bounds {
|
||||
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
|
||||
let bound_id = bound.def_id();
|
||||
let bound_span = self
|
||||
.tcx()
|
||||
let bound_span = tcx
|
||||
.associated_items(bound_id)
|
||||
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, bound_id)
|
||||
.and_then(|item| self.tcx().hir().span_if_local(item.def_id));
|
||||
.find_by_name_and_kind(tcx, assoc_name, assoc_kind, bound_id)
|
||||
.and_then(|item| tcx.hir().span_if_local(item.def_id));
|
||||
|
||||
if let Some(bound_span) = bound_span {
|
||||
err.span_label(
|
||||
bound_span,
|
||||
format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
|
||||
);
|
||||
if let Some(constraint) = &is_equality {
|
||||
where_bounds.push(format!(
|
||||
" T: {trait}::{assoc_name} = {constraint}",
|
||||
trait=bound.print_only_trait_path(),
|
||||
));
|
||||
if let Some(binding) = binding {
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(term) => {
|
||||
// FIXME(#97583): This isn't syntactically well-formed!
|
||||
where_bounds.push(format!(
|
||||
" T: {trait}::{assoc_name} = {term}",
|
||||
trait = bound.print_only_trait_path(),
|
||||
term = term.node,
|
||||
));
|
||||
}
|
||||
// FIXME: Provide a suggestion.
|
||||
ConvertedBindingKind::Constraint(_bounds) => {}
|
||||
}
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(assoc_name.span.lo()),
|
||||
|
|
@ -1199,7 +1205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
} else {
|
||||
err.note(format!(
|
||||
"associated type `{ty_param_name}` could derive from `{}`",
|
||||
"associated {assoc_kind_str} `{assoc_name}` could derive from `{}`",
|
||||
bound.print_only_trait_path(),
|
||||
));
|
||||
}
|
||||
|
|
@ -1220,46 +1226,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
Ok(bound)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, all_candidates, ty_name), ret)]
|
||||
fn one_bound_for_assoc_method(
|
||||
&self,
|
||||
all_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
ty_name: impl Display,
|
||||
assoc_name: Ident,
|
||||
span: Span,
|
||||
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
|
||||
let mut matching_candidates = all_candidates.filter(|r| {
|
||||
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name)
|
||||
});
|
||||
|
||||
let candidate = match matching_candidates.next() {
|
||||
Some(candidate) => candidate,
|
||||
None => {
|
||||
return Err(self.tcx().sess.emit_err(
|
||||
crate::errors::ReturnTypeNotationMissingMethod {
|
||||
span,
|
||||
ty_name: ty_name.to_string(),
|
||||
assoc_name: assoc_name.name,
|
||||
},
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(conflicting_candidate) = matching_candidates.next() {
|
||||
return Err(self.tcx().sess.emit_err(
|
||||
crate::errors::ReturnTypeNotationConflictingBound {
|
||||
span,
|
||||
ty_name: ty_name.to_string(),
|
||||
assoc_name: assoc_name.name,
|
||||
first_bound: candidate.print_only_trait_path(),
|
||||
second_bound: conflicting_candidate.print_only_trait_path(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
Ok(candidate)
|
||||
}
|
||||
|
||||
// Create a type from a path to an associated type or to an enum variant.
|
||||
// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
|
||||
// and item_segment is the path segment for `D`. We return a type and a def for
|
||||
|
|
@ -1421,7 +1387,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
return Err(guar);
|
||||
};
|
||||
|
||||
self.one_bound_for_assoc_type(
|
||||
self.one_bound_for_assoc_item(
|
||||
|| {
|
||||
traits::supertraits(
|
||||
tcx,
|
||||
|
|
@ -1430,6 +1396,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
},
|
||||
kw::SelfUpper,
|
||||
None,
|
||||
ty::AssocKind::Type,
|
||||
assoc_ident,
|
||||
span,
|
||||
None,
|
||||
|
|
@ -1510,15 +1477,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
};
|
||||
|
||||
let trait_did = bound.def_id();
|
||||
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did)
|
||||
else {
|
||||
// Assume that if it's not matched, there must be a const defined with the same name
|
||||
// but it was used in a type position.
|
||||
let msg = format!("found associated const `{assoc_ident}` when type was expected");
|
||||
let guar = tcx.sess.struct_span_err(span, msg).emit();
|
||||
return Err(guar);
|
||||
};
|
||||
|
||||
let assoc_ty_did = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap();
|
||||
let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
|
||||
|
||||
if let Some(variant_def_id) = variant_resolution {
|
||||
|
|
@ -1731,8 +1690,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let tcx = self.tcx();
|
||||
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(name, scope, block);
|
||||
|
||||
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
|
||||
// of calling `find_by_name_and_kind`.
|
||||
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
|
||||
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
|
||||
// `ident` again and again.
|
||||
let item = tcx.associated_items(scope).in_definition_order().find(|i| {
|
||||
i.kind.namespace() == Namespace::TypeNS
|
||||
&& i.ident(tcx).normalize_to_macros_2_0() == ident
|
||||
|
|
@ -2858,3 +2818,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
Some(r)
|
||||
}
|
||||
}
|
||||
|
||||
fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
|
||||
match kind {
|
||||
ty::AssocKind::Fn => "function",
|
||||
ty::AssocKind::Const => "constant",
|
||||
ty::AssocKind::Type => "type",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -521,6 +521,8 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
|
|||
sym::simd_fpowi => (1, 0, vec![param(0), tcx.types.i32], param(0)),
|
||||
sym::simd_fma => (1, 0, vec![param(0), param(0), param(0)], param(0)),
|
||||
sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)),
|
||||
sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)),
|
||||
sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)),
|
||||
sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)),
|
||||
sym::simd_insert => (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)),
|
||||
sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)),
|
||||
|
|
|
|||
|
|
@ -6,9 +6,121 @@ use rustc_errors::{
|
|||
MultiSpan,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_ambiguous_assoc_item)]
|
||||
pub struct AmbiguousAssocItem<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub assoc_kind: &'static str,
|
||||
pub assoc_name: Ident,
|
||||
pub ty_param_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_assoc_kind_mismatch)]
|
||||
pub struct AssocKindMismatch {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub expected: &'static str,
|
||||
pub got: &'static str,
|
||||
#[label(hir_analysis_expected_because_label)]
|
||||
pub expected_because_label: Option<Span>,
|
||||
pub assoc_kind: &'static str,
|
||||
#[note]
|
||||
pub def_span: Span,
|
||||
#[label(hir_analysis_bound_on_assoc_const_label)]
|
||||
pub bound_on_assoc_const_label: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub wrap_in_braces_sugg: Option<AssocKindMismatchWrapInBracesSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub struct AssocKindMismatchWrapInBracesSugg {
|
||||
#[suggestion_part(code = "{{ ")]
|
||||
pub lo: Span,
|
||||
#[suggestion_part(code = " }}")]
|
||||
pub hi: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_assoc_item_not_found, code = "E0220")]
|
||||
pub struct AssocItemNotFound<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub assoc_name: Ident,
|
||||
pub assoc_kind: &'static str,
|
||||
pub ty_param_name: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub label: Option<AssocItemNotFoundLabel<'a>>,
|
||||
#[subdiagnostic]
|
||||
pub sugg: Option<AssocItemNotFoundSugg<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum AssocItemNotFoundLabel<'a> {
|
||||
#[label(hir_analysis_assoc_item_not_found_label)]
|
||||
NotFound {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(hir_analysis_assoc_item_not_found_found_in_other_trait_label)]
|
||||
FoundInOtherTrait {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
assoc_kind: &'static str,
|
||||
trait_name: &'a str,
|
||||
suggested_name: Symbol,
|
||||
identically_named: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
||||
pub enum AssocItemNotFoundSugg<'a> {
|
||||
#[suggestion(
|
||||
hir_analysis_assoc_item_not_found_similar_sugg,
|
||||
code = "{suggested_name}",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Similar {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
assoc_kind: &'static str,
|
||||
suggested_name: Symbol,
|
||||
},
|
||||
#[suggestion(
|
||||
hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg,
|
||||
code = "{suggested_name}",
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
SimilarInOtherTrait {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
assoc_kind: &'static str,
|
||||
suggested_name: Symbol,
|
||||
},
|
||||
#[suggestion(hir_analysis_assoc_item_not_found_other_sugg, code = "{suggested_name}")]
|
||||
Other {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[applicability]
|
||||
applicability: Applicability,
|
||||
ty_param_name: &'a str,
|
||||
assoc_kind: &'static str,
|
||||
suggested_name: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")]
|
||||
pub struct UnrecognizedAtomicOperation<'a> {
|
||||
|
|
@ -537,27 +649,6 @@ pub(crate) struct ReturnTypeNotationEqualityBound {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_return_type_notation_missing_method)]
|
||||
pub(crate) struct ReturnTypeNotationMissingMethod {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty_name: String,
|
||||
pub assoc_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_return_type_notation_conflicting_bound)]
|
||||
#[note]
|
||||
pub(crate) struct ReturnTypeNotationConflictingBound<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty_name: String,
|
||||
pub assoc_name: Symbol,
|
||||
pub first_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
||||
pub second_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")]
|
||||
pub(crate) struct PlaceholderNotAllowedItemSignatures {
|
||||
|
|
@ -954,15 +1045,6 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
|
|||
pub return_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_assoc_bound_on_const)]
|
||||
#[note]
|
||||
pub struct AssocBoundOnConst {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub descr: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_inherent_ty_outside, code = "E0390")]
|
||||
#[help]
|
||||
|
|
|
|||
|
|
@ -67,6 +67,28 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
|
||||
yield_ty
|
||||
}
|
||||
// HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly
|
||||
// guide inference on the yield type so that we can handle `AsyncIterator`
|
||||
// in this block in projection correctly. In the new trait solver, it is
|
||||
// not a problem.
|
||||
hir::CoroutineKind::AsyncGen(..) => {
|
||||
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span,
|
||||
});
|
||||
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
|
||||
|
||||
Ty::new_adt(
|
||||
tcx,
|
||||
tcx.adt_def(tcx.require_lang_item(hir::LangItem::Poll, Some(span))),
|
||||
tcx.mk_args(&[Ty::new_adt(
|
||||
tcx,
|
||||
tcx.adt_def(tcx.require_lang_item(hir::LangItem::Option, Some(span))),
|
||||
tcx.mk_args(&[yield_ty.into()]),
|
||||
)
|
||||
.into()]),
|
||||
)
|
||||
}
|
||||
hir::CoroutineKind::Async(..) => Ty::new_unit(tcx),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -657,19 +657,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::NormalizesTo(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
// N.B., this predicate is created by breaking down a
|
||||
// `ClosureType: FnFoo()` predicate, where
|
||||
// `ClosureType` represents some `Closure`. It can't
|
||||
// possibly be referring to the current closure,
|
||||
// because we haven't produced the `Closure` for
|
||||
// this closure yet; this is exactly why the other
|
||||
// code is looking for a self type of an unresolved
|
||||
// inference variable.
|
||||
| ty::PredicateKind::Ambiguous
|
||||
=> None,
|
||||
| ty::PredicateKind::Ambiguous => None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -771,6 +763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let args = self.fresh_args_for_item(span, def_id);
|
||||
let ty = item_ty.instantiate(self.tcx, args);
|
||||
|
||||
self.write_args(hir_id, args);
|
||||
self.write_resolution(hir_id, Ok((def_kind, def_id)));
|
||||
|
||||
let code = match lang_item {
|
||||
|
|
|
|||
|
|
@ -1591,10 +1591,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity();
|
||||
sig.inputs().skip_binder().get(0).and_then(|first| {
|
||||
if first.peel_refs() == rcvr_ty.peel_refs() {
|
||||
None
|
||||
} else {
|
||||
let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity();
|
||||
// if the type of first arg is the same as the current impl type, we should take the first arg into assoc function
|
||||
if first.peel_refs() == impl_ty {
|
||||
Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin
|
|||
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;
|
||||
|
||||
|
|
@ -459,7 +460,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
ambient_variance,
|
||||
)?;
|
||||
|
||||
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
|
||||
// Constrain `b_vid` to the generalized type `b_ty`.
|
||||
if let &ty::Infer(TyVar(b_ty_vid)) = b_ty.kind() {
|
||||
self.infcx.inner.borrow_mut().type_variables().equate(b_vid, b_ty_vid);
|
||||
} else {
|
||||
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
|
||||
}
|
||||
|
||||
if needs_wf {
|
||||
self.obligations.push(Obligation::new(
|
||||
|
|
@ -484,31 +490,46 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
// cyclic type. We instead delay the unification in case
|
||||
// the alias can be normalized to something which does not
|
||||
// mention `?0`.
|
||||
|
||||
// FIXME(-Ztrait-solver=next): replace this with `AliasRelate`
|
||||
let &ty::Alias(kind, data) = a_ty.kind() else {
|
||||
bug!("generalization should only result in infer vars for aliases");
|
||||
};
|
||||
if !self.infcx.next_trait_solver() {
|
||||
// The old solver only accepts projection predicates for associated types.
|
||||
match kind {
|
||||
ty::AliasKind::Projection => {}
|
||||
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque => {
|
||||
return Err(TypeError::CyclicTy(a_ty));
|
||||
if self.infcx.next_trait_solver() {
|
||||
let (lhs, rhs, direction) = match ambient_variance {
|
||||
ty::Variance::Invariant => {
|
||||
(a_ty.into(), b_ty.into(), AliasRelationDirection::Equate)
|
||||
}
|
||||
ty::Variance::Covariant => {
|
||||
(a_ty.into(), b_ty.into(), AliasRelationDirection::Subtype)
|
||||
}
|
||||
ty::Variance::Contravariant => {
|
||||
(b_ty.into(), a_ty.into(), AliasRelationDirection::Subtype)
|
||||
}
|
||||
ty::Variance::Bivariant => unreachable!("bivariant generalization"),
|
||||
};
|
||||
self.obligations.push(Obligation::new(
|
||||
self.tcx(),
|
||||
self.trace.cause.clone(),
|
||||
self.param_env,
|
||||
ty::PredicateKind::AliasRelate(lhs, rhs, direction),
|
||||
));
|
||||
} else {
|
||||
match a_ty.kind() {
|
||||
&ty::Alias(ty::AliasKind::Projection, data) => {
|
||||
// FIXME: This does not handle subtyping correctly, we could
|
||||
// instead create a new inference variable for `a_ty`, emitting
|
||||
// `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
|
||||
self.obligations.push(Obligation::new(
|
||||
self.tcx(),
|
||||
self.trace.cause.clone(),
|
||||
self.param_env,
|
||||
ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() },
|
||||
))
|
||||
}
|
||||
// The old solver only accepts projection predicates for associated types.
|
||||
ty::Alias(
|
||||
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque,
|
||||
_,
|
||||
) => return Err(TypeError::CyclicTy(a_ty)),
|
||||
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This does not handle subtyping correctly, we should switch to
|
||||
// alias-relate in the new solver and could instead create a new inference
|
||||
// variable for `a_ty`, emitting `Projection(a_ty, a_infer)` and
|
||||
// `a_infer <: b_ty`.
|
||||
self.obligations.push(Obligation::new(
|
||||
self.tcx(),
|
||||
self.trace.cause.clone(),
|
||||
self.param_env,
|
||||
ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() },
|
||||
))
|
||||
} else {
|
||||
match ambient_variance {
|
||||
ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty),
|
||||
|
|
@ -519,9 +540,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
a_ty,
|
||||
b_ty,
|
||||
),
|
||||
ty::Variance::Bivariant => {
|
||||
unreachable!("no code should be generalizing bivariantly (currently)")
|
||||
}
|
||||
ty::Variance::Bivariant => unreachable!("bivariant generalization"),
|
||||
}?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1181,37 +1181,54 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind(), t2, t2.kind());
|
||||
|
||||
// helper functions
|
||||
fn equals<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
||||
match (a.kind(), b.kind()) {
|
||||
(a, b) if *a == *b => true,
|
||||
(&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_)))
|
||||
| (
|
||||
&ty::Infer(ty::InferTy::IntVar(_)),
|
||||
&ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_)),
|
||||
)
|
||||
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
|
||||
| (
|
||||
&ty::Infer(ty::InferTy::FloatVar(_)),
|
||||
&ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
|
||||
) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
let recurse = |t1, t2, values: &mut (DiagnosticStyledString, DiagnosticStyledString)| {
|
||||
let (x1, x2) = self.cmp(t1, t2);
|
||||
(values.0).0.extend(x1.0);
|
||||
(values.1).0.extend(x2.0);
|
||||
};
|
||||
|
||||
fn push_ty_ref<'tcx>(
|
||||
region: ty::Region<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
mutbl: hir::Mutability,
|
||||
s: &mut DiagnosticStyledString,
|
||||
) {
|
||||
fn fmt_region<'tcx>(region: ty::Region<'tcx>) -> String {
|
||||
let mut r = region.to_string();
|
||||
if r == "'_" {
|
||||
r.clear();
|
||||
} else {
|
||||
r.push(' ');
|
||||
}
|
||||
s.push_highlighted(format!("&{}{}", r, mutbl.prefix_str()));
|
||||
s.push_normal(ty.to_string());
|
||||
format!("&{r}")
|
||||
}
|
||||
|
||||
fn push_ref<'tcx>(
|
||||
region: ty::Region<'tcx>,
|
||||
mutbl: hir::Mutability,
|
||||
s: &mut DiagnosticStyledString,
|
||||
) {
|
||||
s.push_highlighted(fmt_region(region));
|
||||
s.push_highlighted(mutbl.prefix_str());
|
||||
}
|
||||
|
||||
fn cmp_ty_refs<'tcx>(
|
||||
r1: ty::Region<'tcx>,
|
||||
mut1: hir::Mutability,
|
||||
r2: ty::Region<'tcx>,
|
||||
mut2: hir::Mutability,
|
||||
ss: &mut (DiagnosticStyledString, DiagnosticStyledString),
|
||||
) {
|
||||
let (r1, r2) = (fmt_region(r1), fmt_region(r2));
|
||||
if r1 != r2 {
|
||||
ss.0.push_highlighted(r1);
|
||||
ss.1.push_highlighted(r2);
|
||||
} else {
|
||||
ss.0.push_normal(r1);
|
||||
ss.1.push_normal(r2);
|
||||
}
|
||||
|
||||
if mut1 != mut2 {
|
||||
ss.0.push_highlighted(mut1.prefix_str());
|
||||
ss.1.push_highlighted(mut2.prefix_str());
|
||||
} else {
|
||||
ss.0.push_normal(mut1.prefix_str());
|
||||
ss.1.push_normal(mut2.prefix_str());
|
||||
}
|
||||
}
|
||||
|
||||
// process starts here
|
||||
|
|
@ -1310,9 +1327,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
values.0.push_normal("_");
|
||||
values.1.push_normal("_");
|
||||
} else {
|
||||
let (x1, x2) = self.cmp(ta1, ta2);
|
||||
(values.0).0.extend(x1.0);
|
||||
(values.1).0.extend(x2.0);
|
||||
recurse(ta1, ta2, &mut values);
|
||||
}
|
||||
self.push_comma(&mut values.0, &mut values.1, len, i);
|
||||
}
|
||||
|
|
@ -1418,27 +1433,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// When finding T != &T, highlight only the borrow
|
||||
(&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(ref_ty1, t2) => {
|
||||
// When finding `&T != &T`, compare the references, then recurse into pointee type
|
||||
(&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2)) => {
|
||||
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
|
||||
push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0);
|
||||
values.1.push_normal(t2.to_string());
|
||||
cmp_ty_refs(r1, mutbl1, r2, mutbl2, &mut values);
|
||||
recurse(ref_ty1, ref_ty2, &mut values);
|
||||
values
|
||||
}
|
||||
(_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(t1, ref_ty2) => {
|
||||
// When finding T != &T, highlight the borrow
|
||||
(&ty::Ref(r1, ref_ty1, mutbl1), _) => {
|
||||
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
|
||||
values.0.push_normal(t1.to_string());
|
||||
push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1);
|
||||
push_ref(r1, mutbl1, &mut values.0);
|
||||
recurse(ref_ty1, t2, &mut values);
|
||||
values
|
||||
}
|
||||
|
||||
// When encountering &T != &mut T, highlight only the borrow
|
||||
(&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2))
|
||||
if equals(ref_ty1, ref_ty2) =>
|
||||
{
|
||||
(_, &ty::Ref(r2, ref_ty2, mutbl2)) => {
|
||||
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
|
||||
push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0);
|
||||
push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1);
|
||||
push_ref(r2, mutbl2, &mut values.1);
|
||||
recurse(t1, ref_ty2, &mut values);
|
||||
values
|
||||
}
|
||||
|
||||
|
|
@ -1448,9 +1460,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
(DiagnosticStyledString::normal("("), DiagnosticStyledString::normal("("));
|
||||
let len = args1.len();
|
||||
for (i, (left, right)) in args1.iter().zip(args2).enumerate() {
|
||||
let (x1, x2) = self.cmp(left, right);
|
||||
(values.0).0.extend(x1.0);
|
||||
(values.1).0.extend(x2.0);
|
||||
recurse(left, right, &mut values);
|
||||
self.push_comma(&mut values.0, &mut values.1, len, i);
|
||||
}
|
||||
if len == 1 {
|
||||
|
|
|
|||
|
|
@ -345,37 +345,61 @@ pub struct InferCtxt<'tcx> {
|
|||
impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
|
||||
type Interner = TyCtxt<'tcx>;
|
||||
|
||||
fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> {
|
||||
use InferTy::*;
|
||||
match ty {
|
||||
// FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
|
||||
// ty infers will give you the universe of the var it resolved to not the universe
|
||||
// it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
|
||||
// try to print out `?0.1` it will just print `?0`.
|
||||
TyVar(ty_vid) => match self.probe_ty_var(ty_vid) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
},
|
||||
IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => None,
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn universe_of_ty(&self, vid: TyVid) -> Option<ty::UniverseIndex> {
|
||||
// FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
|
||||
// ty infers will give you the universe of the var it resolved to not the universe
|
||||
// it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
|
||||
// try to print out `?0.1` it will just print `?0`.
|
||||
match self.probe_ty_var(vid) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_ct(&self, ct: ty::InferConst) -> Option<ty::UniverseIndex> {
|
||||
use ty::InferConst::*;
|
||||
match ct {
|
||||
// Same issue as with `universe_of_ty`
|
||||
Var(ct_vid) => match self.probe_const_var(ct_vid) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
},
|
||||
EffectVar(_) => None,
|
||||
Fresh(_) => None,
|
||||
fn universe_of_ct(&self, ct: ConstVid) -> Option<ty::UniverseIndex> {
|
||||
// Same issue as with `universe_of_ty`
|
||||
match self.probe_const_var(ct) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||
Some(self.universe_of_region_vid(lt))
|
||||
}
|
||||
|
||||
fn root_ty_var(&self, vid: TyVid) -> TyVid {
|
||||
self.root_var(vid)
|
||||
}
|
||||
|
||||
fn probe_ty_var(&self, vid: TyVid) -> Option<Ty<'tcx>> {
|
||||
self.probe_ty_var(vid).ok()
|
||||
}
|
||||
|
||||
fn root_lt_var(&self, vid: ty::RegionVid) -> ty::RegionVid {
|
||||
self.root_region_var(vid)
|
||||
}
|
||||
|
||||
fn probe_lt_var(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
|
||||
let re = self
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.tcx, vid);
|
||||
if re.is_var() { None } else { Some(re) }
|
||||
}
|
||||
|
||||
fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
|
||||
self.root_const_var(vid)
|
||||
}
|
||||
|
||||
fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
|
||||
self.probe_const_var(vid).ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// See the `error_reporting` module for more details.
|
||||
|
|
@ -1347,6 +1371,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
self.inner.borrow_mut().type_variables().root_var(var)
|
||||
}
|
||||
|
||||
pub fn root_region_var(&self, var: ty::RegionVid) -> ty::RegionVid {
|
||||
self.inner.borrow_mut().unwrap_region_constraints().root_var(var)
|
||||
}
|
||||
|
||||
pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
|
||||
self.inner.borrow_mut().const_unification_table().find(var).vid
|
||||
}
|
||||
|
|
|
|||
|
|
@ -623,6 +623,11 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn root_var(&mut self, vid: ty::RegionVid) -> ty::RegionVid {
|
||||
let mut ut = self.unification_table_mut(); // FIXME(rust-lang/ena#42): unnecessary mut
|
||||
ut.find(vid).vid
|
||||
}
|
||||
|
||||
fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
|
||||
match t {
|
||||
Glb => &mut self.glbs,
|
||||
|
|
|
|||
|
|
@ -229,12 +229,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
|
|||
/// Precondition: `vid` must not have been previously instantiated.
|
||||
pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
|
||||
let vid = self.root_var(vid);
|
||||
debug_assert!(!ty.is_ty_var(), "instantiating ty var with var: {vid:?} {ty:?}");
|
||||
debug_assert!(self.probe(vid).is_unknown());
|
||||
debug_assert!(
|
||||
self.eq_relations().probe_value(vid).is_unknown(),
|
||||
"instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
|
||||
vid,
|
||||
ty,
|
||||
"instantiating type variable `{vid:?}` twice: new-value = {ty:?}, old-value={:?}",
|
||||
self.eq_relations().probe_value(vid)
|
||||
);
|
||||
self.eq_relations().union_value(vid, TypeVariableValue::Known { value: ty });
|
||||
|
|
|
|||
|
|
@ -261,9 +261,14 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
|||
fn elaborate(&mut self, elaboratable: &O) {
|
||||
let tcx = self.visited.tcx;
|
||||
|
||||
let bound_predicate = elaboratable.predicate().kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
|
||||
// We only elaborate clauses.
|
||||
let Some(clause) = elaboratable.predicate().as_clause() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let bound_clause = clause.kind();
|
||||
match bound_clause.skip_binder() {
|
||||
ty::ClauseKind::Trait(data) => {
|
||||
// Negative trait bounds do not imply any supertrait bounds
|
||||
if data.polarity == ty::ImplPolarity::Negative {
|
||||
return;
|
||||
|
|
@ -280,49 +285,16 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
|||
let obligations =
|
||||
predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
|
||||
elaboratable.child_with_derived_cause(
|
||||
clause.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
|
||||
clause.subst_supertrait(tcx, &bound_clause.rebind(data.trait_ref)),
|
||||
span,
|
||||
bound_predicate.rebind(data),
|
||||
bound_clause.rebind(data),
|
||||
index,
|
||||
)
|
||||
});
|
||||
debug!(?data, ?obligations, "super_predicates");
|
||||
self.extend_deduped(obligations);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => {
|
||||
// Currently, we do not elaborate WF predicates,
|
||||
// although we easily could.
|
||||
}
|
||||
ty::PredicateKind::ObjectSafe(..) => {
|
||||
// Currently, we do not elaborate object-safe
|
||||
// predicates.
|
||||
}
|
||||
ty::PredicateKind::Subtype(..) => {
|
||||
// Currently, we do not "elaborate" predicates like `X <: Y`,
|
||||
// though conceivably we might.
|
||||
}
|
||||
ty::PredicateKind::Coerce(..) => {
|
||||
// Currently, we do not "elaborate" predicates like `X -> Y`,
|
||||
// though conceivably we might.
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => {
|
||||
// Nothing to elaborate in a projection predicate.
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => {
|
||||
// Currently, we do not elaborate const-evaluatable
|
||||
// predicates.
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(..) => {
|
||||
// Currently, we do not elaborate const-equate
|
||||
// predicates.
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => {
|
||||
// Nothing to elaborate from `'a: 'b`.
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
|
||||
ty_max,
|
||||
r_min,
|
||||
))) => {
|
||||
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
|
||||
// We know that `T: 'a` for some type `T`. We can
|
||||
// often elaborate this. For example, if we know that
|
||||
// `[U]: 'a`, that implies that `U: 'a`. Similarly, if
|
||||
|
|
@ -385,15 +357,25 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
|||
}
|
||||
})
|
||||
.map(|clause| {
|
||||
elaboratable.child(bound_predicate.rebind(clause).to_predicate(tcx))
|
||||
elaboratable.child(bound_clause.rebind(clause).to_predicate(tcx))
|
||||
}),
|
||||
);
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::AliasRelate(..) => {
|
||||
// No
|
||||
ty::ClauseKind::RegionOutlives(..) => {
|
||||
// Nothing to elaborate from `'a: 'b`.
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => {
|
||||
ty::ClauseKind::WellFormed(..) => {
|
||||
// Currently, we do not elaborate WF predicates,
|
||||
// although we easily could.
|
||||
}
|
||||
ty::ClauseKind::Projection(..) => {
|
||||
// Nothing to elaborate in a projection predicate.
|
||||
}
|
||||
ty::ClauseKind::ConstEvaluatable(..) => {
|
||||
// Currently, we do not elaborate const-evaluatable
|
||||
// predicates.
|
||||
}
|
||||
ty::ClauseKind::ConstArgHasType(..) => {
|
||||
// Nothing to elaborate
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -316,6 +316,10 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
|||
// Set parallel mode before thread pool creation, which will create `Lock`s.
|
||||
rustc_data_structures::sync::set_dyn_thread_safe_mode(config.opts.unstable_opts.threads > 1);
|
||||
|
||||
// Check jobserver before run_in_thread_pool_with_globals, which call jobserver::acquire_thread
|
||||
let early_handler = EarlyErrorHandler::new(config.opts.error_format);
|
||||
early_handler.initialize_checked_jobserver();
|
||||
|
||||
util::run_in_thread_pool_with_globals(
|
||||
config.opts.edition,
|
||||
config.opts.unstable_opts.threads,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ use std::sync::Arc;
|
|||
|
||||
fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
|
||||
let mut early_handler = EarlyErrorHandler::new(ErrorOutputType::default());
|
||||
early_handler.initialize_checked_jobserver();
|
||||
|
||||
let registry = registry::Registry::new(&[]);
|
||||
let sessopts = build_session_options(&mut early_handler, &matches);
|
||||
let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,14 @@
|
|||
use std::ops::Range;
|
||||
use std::str::Chars;
|
||||
|
||||
use Mode::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// Errors and warnings that can occur during string unescaping.
|
||||
/// Errors and warnings that can occur during string unescaping. They mostly
|
||||
/// relate to malformed escape sequences, but there are a few that are about
|
||||
/// other problems.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum EscapeError {
|
||||
/// Expected 1 char, but 0 were found.
|
||||
|
|
@ -73,25 +77,24 @@ impl EscapeError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Takes a contents of a literal (without quotes) and produces a
|
||||
/// sequence of escaped characters or errors.
|
||||
/// Values are returned through invoking of the provided callback.
|
||||
/// Takes a contents of a literal (without quotes) and produces a sequence of
|
||||
/// escaped characters or errors.
|
||||
///
|
||||
/// Values are returned by invoking `callback`. For `Char` and `Byte` modes,
|
||||
/// the callback will be called exactly once.
|
||||
pub fn unescape_literal<F>(src: &str, mode: Mode, callback: &mut F)
|
||||
where
|
||||
F: FnMut(Range<usize>, Result<char, EscapeError>),
|
||||
{
|
||||
match mode {
|
||||
Mode::Char | Mode::Byte => {
|
||||
Char | Byte => {
|
||||
let mut chars = src.chars();
|
||||
let res = unescape_char_or_byte(&mut chars, mode == Mode::Byte);
|
||||
let res = unescape_char_or_byte(&mut chars, mode);
|
||||
callback(0..(src.len() - chars.as_str().len()), res);
|
||||
}
|
||||
Mode::Str | Mode::ByteStr => unescape_str_common(src, mode, callback),
|
||||
|
||||
Mode::RawStr | Mode::RawByteStr => {
|
||||
unescape_raw_str_or_raw_byte_str(src, mode == Mode::RawByteStr, callback)
|
||||
}
|
||||
Mode::CStr | Mode::RawCStr => unreachable!(),
|
||||
Str | ByteStr => unescape_str_common(src, mode, callback),
|
||||
RawStr | RawByteStr => unescape_raw_str_or_raw_byte_str(src, mode, callback),
|
||||
CStr | RawCStr => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,38 +120,44 @@ pub fn unescape_c_string<F>(src: &str, mode: Mode, callback: &mut F)
|
|||
where
|
||||
F: FnMut(Range<usize>, Result<CStrUnit, EscapeError>),
|
||||
{
|
||||
if mode == Mode::RawCStr {
|
||||
unescape_raw_str_or_raw_byte_str(
|
||||
src,
|
||||
mode.characters_should_be_ascii(),
|
||||
&mut |r, result| callback(r, result.map(CStrUnit::Char)),
|
||||
);
|
||||
} else {
|
||||
unescape_str_common(src, mode, callback);
|
||||
match mode {
|
||||
CStr => {
|
||||
unescape_str_common(src, mode, callback);
|
||||
}
|
||||
RawCStr => {
|
||||
unescape_raw_str_or_raw_byte_str(src, mode, &mut |r, result| {
|
||||
callback(r, result.map(CStrUnit::Char))
|
||||
});
|
||||
}
|
||||
Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes a contents of a char literal (without quotes), and returns an
|
||||
/// unescaped char or an error.
|
||||
pub fn unescape_char(src: &str) -> Result<char, EscapeError> {
|
||||
unescape_char_or_byte(&mut src.chars(), false)
|
||||
unescape_char_or_byte(&mut src.chars(), Char)
|
||||
}
|
||||
|
||||
/// Takes a contents of a byte literal (without quotes), and returns an
|
||||
/// unescaped byte or an error.
|
||||
pub fn unescape_byte(src: &str) -> Result<u8, EscapeError> {
|
||||
unescape_char_or_byte(&mut src.chars(), true).map(byte_from_char)
|
||||
unescape_char_or_byte(&mut src.chars(), Byte).map(byte_from_char)
|
||||
}
|
||||
|
||||
/// What kind of literal do we parse.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Mode {
|
||||
Char,
|
||||
Str,
|
||||
|
||||
Byte,
|
||||
ByteStr,
|
||||
|
||||
Str,
|
||||
RawStr,
|
||||
|
||||
ByteStr,
|
||||
RawByteStr,
|
||||
|
||||
CStr,
|
||||
RawCStr,
|
||||
}
|
||||
|
|
@ -156,45 +165,42 @@ pub enum Mode {
|
|||
impl Mode {
|
||||
pub fn in_double_quotes(self) -> bool {
|
||||
match self {
|
||||
Mode::Str
|
||||
| Mode::ByteStr
|
||||
| Mode::RawStr
|
||||
| Mode::RawByteStr
|
||||
| Mode::CStr
|
||||
| Mode::RawCStr => true,
|
||||
Mode::Char | Mode::Byte => false,
|
||||
Str | RawStr | ByteStr | RawByteStr | CStr | RawCStr => true,
|
||||
Char | Byte => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Non-byte literals should have `\xXX` escapes that are within the ASCII range.
|
||||
pub fn ascii_escapes_should_be_ascii(self) -> bool {
|
||||
fn ascii_escapes_should_be_ascii(self) -> bool {
|
||||
match self {
|
||||
Mode::Char | Mode::Str | Mode::RawStr => true,
|
||||
Mode::Byte | Mode::ByteStr | Mode::RawByteStr | Mode::CStr | Mode::RawCStr => false,
|
||||
Char | Str => true,
|
||||
Byte | ByteStr | CStr => false,
|
||||
RawStr | RawByteStr | RawCStr => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether characters within the literal must be within the ASCII range
|
||||
pub fn characters_should_be_ascii(self) -> bool {
|
||||
/// Whether characters within the literal must be within the ASCII range.
|
||||
#[inline]
|
||||
fn chars_should_be_ascii(self) -> bool {
|
||||
match self {
|
||||
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
|
||||
Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
|
||||
Byte | ByteStr | RawByteStr => true,
|
||||
Char | Str | RawStr | CStr | RawCStr => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Byte literals do not allow unicode escape.
|
||||
pub fn is_unicode_escape_disallowed(self) -> bool {
|
||||
fn is_unicode_escape_disallowed(self) -> bool {
|
||||
match self {
|
||||
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
|
||||
Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
|
||||
Byte | ByteStr | RawByteStr => true,
|
||||
Char | Str | RawStr | CStr | RawCStr => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prefix_noraw(self) -> &'static str {
|
||||
match self {
|
||||
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => "b",
|
||||
Mode::CStr | Mode::RawCStr => "c",
|
||||
Mode::Char | Mode::Str | Mode::RawStr => "",
|
||||
Char | Str | RawStr => "",
|
||||
Byte | ByteStr | RawByteStr => "b",
|
||||
CStr | RawCStr => "c",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -294,22 +300,21 @@ fn scan_unicode(
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn ascii_check(c: char, characters_should_be_ascii: bool) -> Result<char, EscapeError> {
|
||||
if characters_should_be_ascii && !c.is_ascii() {
|
||||
// Byte literal can't be a non-ascii character.
|
||||
fn ascii_check(c: char, chars_should_be_ascii: bool) -> Result<char, EscapeError> {
|
||||
if chars_should_be_ascii && !c.is_ascii() {
|
||||
Err(EscapeError::NonAsciiCharInByte)
|
||||
} else {
|
||||
Ok(c)
|
||||
}
|
||||
}
|
||||
|
||||
fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
|
||||
fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
|
||||
let c = chars.next().ok_or(EscapeError::ZeroChars)?;
|
||||
let res = match c {
|
||||
'\\' => scan_escape(chars, if is_byte { Mode::Byte } else { Mode::Char }),
|
||||
'\\' => scan_escape(chars, mode),
|
||||
'\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar),
|
||||
'\r' => Err(EscapeError::BareCarriageReturn),
|
||||
_ => ascii_check(c, is_byte),
|
||||
_ => ascii_check(c, mode.chars_should_be_ascii()),
|
||||
}?;
|
||||
if chars.next().is_some() {
|
||||
return Err(EscapeError::MoreThanOneChar);
|
||||
|
|
@ -324,6 +329,7 @@ where
|
|||
F: FnMut(Range<usize>, Result<T, EscapeError>),
|
||||
{
|
||||
let mut chars = src.chars();
|
||||
let chars_should_be_ascii = mode.chars_should_be_ascii(); // get this outside the loop
|
||||
|
||||
// The `start` and `end` computation here is complicated because
|
||||
// `skip_ascii_whitespace` makes us to skip over chars without counting
|
||||
|
|
@ -346,14 +352,12 @@ where
|
|||
_ => scan_escape::<T>(&mut chars, mode),
|
||||
}
|
||||
}
|
||||
'\n' => Ok(b'\n'.into()),
|
||||
'\t' => Ok(b'\t'.into()),
|
||||
'"' => Err(EscapeError::EscapeOnlyChar),
|
||||
'\r' => Err(EscapeError::BareCarriageReturn),
|
||||
_ => ascii_check(c, mode.characters_should_be_ascii()).map(Into::into),
|
||||
_ => ascii_check(c, chars_should_be_ascii).map(Into::into),
|
||||
};
|
||||
let end = src.len() - chars.as_str().len();
|
||||
callback(start..end, res.map(Into::into));
|
||||
callback(start..end, res);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -387,20 +391,21 @@ where
|
|||
/// sequence of characters or errors.
|
||||
/// NOTE: Raw strings do not perform any explicit character escaping, here we
|
||||
/// only produce errors on bare CR.
|
||||
fn unescape_raw_str_or_raw_byte_str<F>(src: &str, is_byte: bool, callback: &mut F)
|
||||
fn unescape_raw_str_or_raw_byte_str<F>(src: &str, mode: Mode, callback: &mut F)
|
||||
where
|
||||
F: FnMut(Range<usize>, Result<char, EscapeError>),
|
||||
{
|
||||
let mut chars = src.chars();
|
||||
let chars_should_be_ascii = mode.chars_should_be_ascii(); // get this outside the loop
|
||||
|
||||
// The `start` and `end` computation here matches the one in
|
||||
// `unescape_str_or_byte_str` for consistency, even though this function
|
||||
// `unescape_str_common` for consistency, even though this function
|
||||
// doesn't have to worry about skipping any chars.
|
||||
while let Some(c) = chars.next() {
|
||||
let start = src.len() - chars.as_str().len() - c.len_utf8();
|
||||
let res = match c {
|
||||
'\r' => Err(EscapeError::BareCarriageReturnInRawString),
|
||||
_ => ascii_check(c, is_byte),
|
||||
_ => ascii_check(c, chars_should_be_ascii),
|
||||
};
|
||||
let end = src.len() - chars.as_str().len();
|
||||
callback(start..end, res);
|
||||
|
|
@ -410,7 +415,7 @@ where
|
|||
#[inline]
|
||||
pub fn byte_from_char(c: char) -> u8 {
|
||||
let res = c as u32;
|
||||
debug_assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr");
|
||||
debug_assert!(res <= u8::MAX as u32, "guaranteed because of ByteStr");
|
||||
res as u8
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1000,8 +1000,10 @@ impl EarlyLintPass for UnusedDocComment {
|
|||
}
|
||||
|
||||
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
|
||||
let arm_span = arm.pat.span.with_hi(arm.body.span.hi());
|
||||
warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
|
||||
if let Some(body) = &arm.body {
|
||||
let arm_span = arm.pat.span.with_hi(body.span.hi());
|
||||
warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
|
||||
|
|
|
|||
|
|
@ -162,12 +162,8 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
|||
// Explicitly check for lints associated with 'closure_id', since
|
||||
// it does not have a corresponding AST node
|
||||
if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
|
||||
if let Some(
|
||||
ast::CoroutineKind::Async { closure_id, .. }
|
||||
| ast::CoroutineKind::Gen { closure_id, .. },
|
||||
) = sig.header.coro_kind
|
||||
{
|
||||
self.check_id(closure_id);
|
||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||
self.check_id(coroutine_kind.closure_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -227,13 +223,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
|||
// it does not have a corresponding AST node
|
||||
match e.kind {
|
||||
ast::ExprKind::Closure(box ast::Closure {
|
||||
coro_kind:
|
||||
Some(
|
||||
ast::CoroutineKind::Async { closure_id, .. }
|
||||
| ast::CoroutineKind::Gen { closure_id, .. },
|
||||
),
|
||||
coroutine_kind: Some(coroutine_kind),
|
||||
..
|
||||
}) => self.check_id(closure_id),
|
||||
}) => {
|
||||
self.check_id(coroutine_kind.closure_id());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
lint_callback!(self, check_expr_post, e);
|
||||
|
|
|
|||
|
|
@ -1113,15 +1113,17 @@ impl EarlyLintPass for UnusedParens {
|
|||
}
|
||||
ExprKind::Match(ref _expr, ref arm) => {
|
||||
for a in arm {
|
||||
self.check_unused_delims_expr(
|
||||
cx,
|
||||
&a.body,
|
||||
UnusedDelimsCtx::MatchArmExpr,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
);
|
||||
if let Some(body) = &a.body {
|
||||
self.check_unused_delims_expr(
|
||||
cx,
|
||||
body,
|
||||
UnusedDelimsCtx::MatchArmExpr,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
|||
const char *SplitDwarfFile,
|
||||
const char *OutputObjFile,
|
||||
const char *DebugInfoCompression,
|
||||
bool ForceEmulatedTls,
|
||||
bool UseEmulatedTls,
|
||||
const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
|
||||
|
||||
auto OptLevel = fromRust(RustOptLevel);
|
||||
|
|
@ -456,13 +456,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
|||
Options.UseInitArray = UseInitArray;
|
||||
|
||||
#if LLVM_VERSION_LT(17, 0)
|
||||
if (ForceEmulatedTls) {
|
||||
Options.ExplicitEmulatedTLS = true;
|
||||
Options.EmulatedTLS = true;
|
||||
}
|
||||
#else
|
||||
Options.EmulatedTLS = ForceEmulatedTls || Trip.hasDefaultEmulatedTLS();
|
||||
Options.ExplicitEmulatedTLS = true;
|
||||
#endif
|
||||
Options.EmulatedTLS = UseEmulatedTls;
|
||||
|
||||
if (TrapUnreachable) {
|
||||
// Tell LLVM to codegen `unreachable` into an explicit trap instruction.
|
||||
|
|
|
|||
|
|
@ -349,10 +349,6 @@ impl ScopeTree {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn opt_destruction_scope(&self, n: hir::ItemLocalId) -> Option<Scope> {
|
||||
self.destruction_scopes.get(&n).cloned()
|
||||
}
|
||||
|
||||
pub fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: Scope) {
|
||||
debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
|
||||
assert!(var != lifetime.item_local_id());
|
||||
|
|
|
|||
|
|
@ -76,6 +76,13 @@ impl Debug for CovTerm {
|
|||
|
||||
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum CoverageKind {
|
||||
/// Marks a span that might otherwise not be represented in MIR, so that
|
||||
/// coverage instrumentation can associate it with its enclosing block/BCB.
|
||||
///
|
||||
/// Only used by the `InstrumentCoverage` pass, and has no effect during
|
||||
/// codegen.
|
||||
SpanMarker,
|
||||
|
||||
/// Marks the point in MIR control flow represented by a coverage counter.
|
||||
///
|
||||
/// This is eventually lowered to `llvm.instrprof.increment` in LLVM IR.
|
||||
|
|
@ -99,6 +106,7 @@ impl Debug for CoverageKind {
|
|||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
use CoverageKind::*;
|
||||
match self {
|
||||
SpanMarker => write!(fmt, "SpanMarker"),
|
||||
CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()),
|
||||
ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,11 +150,17 @@ impl<O> AssertKind<O> {
|
|||
RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
|
||||
ResumedAfterReturn(CoroutineKind::Coroutine) => "coroutine resumed after completion",
|
||||
ResumedAfterReturn(CoroutineKind::Async(_)) => "`async fn` resumed after completion",
|
||||
ResumedAfterReturn(CoroutineKind::AsyncGen(_)) => {
|
||||
"`async gen fn` resumed after completion"
|
||||
}
|
||||
ResumedAfterReturn(CoroutineKind::Gen(_)) => {
|
||||
"`gen fn` should just keep returning `None` after completion"
|
||||
}
|
||||
ResumedAfterPanic(CoroutineKind::Coroutine) => "coroutine resumed after panicking",
|
||||
ResumedAfterPanic(CoroutineKind::Async(_)) => "`async fn` resumed after panicking",
|
||||
ResumedAfterPanic(CoroutineKind::AsyncGen(_)) => {
|
||||
"`async gen fn` resumed after panicking"
|
||||
}
|
||||
ResumedAfterPanic(CoroutineKind::Gen(_)) => {
|
||||
"`gen fn` should just keep returning `None` after panicking"
|
||||
}
|
||||
|
|
@ -245,6 +251,7 @@ impl<O> AssertKind<O> {
|
|||
DivisionByZero(_) => middle_assert_divide_by_zero,
|
||||
RemainderByZero(_) => middle_assert_remainder_by_zero,
|
||||
ResumedAfterReturn(CoroutineKind::Async(_)) => middle_assert_async_resume_after_return,
|
||||
ResumedAfterReturn(CoroutineKind::AsyncGen(_)) => todo!(),
|
||||
ResumedAfterReturn(CoroutineKind::Gen(_)) => {
|
||||
bug!("gen blocks can be resumed after they return and will keep returning `None`")
|
||||
}
|
||||
|
|
@ -252,6 +259,7 @@ impl<O> AssertKind<O> {
|
|||
middle_assert_coroutine_resume_after_return
|
||||
}
|
||||
ResumedAfterPanic(CoroutineKind::Async(_)) => middle_assert_async_resume_after_panic,
|
||||
ResumedAfterPanic(CoroutineKind::AsyncGen(_)) => todo!(),
|
||||
ResumedAfterPanic(CoroutineKind::Gen(_)) => middle_assert_gen_resume_after_panic,
|
||||
ResumedAfterPanic(CoroutineKind::Coroutine) => {
|
||||
middle_assert_coroutine_resume_after_panic
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ pub struct Block {
|
|||
/// This does *not* include labels on loops, e.g. `'label: loop {}`.
|
||||
pub targeted_by_break: bool,
|
||||
pub region_scope: region::Scope,
|
||||
pub opt_destruction_scope: Option<region::Scope>,
|
||||
/// The span of the block, including the opening braces,
|
||||
/// the label, and the `unsafe` keyword, if present.
|
||||
pub span: Span,
|
||||
|
|
@ -193,7 +192,6 @@ pub enum BlockSafety {
|
|||
#[derive(Clone, Debug, HashStable)]
|
||||
pub struct Stmt<'tcx> {
|
||||
pub kind: StmtKind<'tcx>,
|
||||
pub opt_destruction_scope: Option<region::Scope>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, HashStable)]
|
||||
|
|
@ -1224,12 +1222,12 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
|||
mod size_asserts {
|
||||
use super::*;
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(Block, 56);
|
||||
static_assert_size!(Block, 48);
|
||||
static_assert_size!(Expr<'_>, 64);
|
||||
static_assert_size!(ExprKind<'_>, 40);
|
||||
static_assert_size!(Pat<'_>, 64);
|
||||
static_assert_size!(PatKind<'_>, 48);
|
||||
static_assert_size!(Stmt<'_>, 56);
|
||||
static_assert_size!(Stmt<'_>, 48);
|
||||
static_assert_size!(StmtKind<'_>, 48);
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,10 +144,14 @@ pub enum SelectionCandidate<'tcx> {
|
|||
/// generated for an async construct.
|
||||
FutureCandidate,
|
||||
|
||||
/// Implementation of an `Iterator` trait by one of the generator types
|
||||
/// generated for a gen construct.
|
||||
/// Implementation of an `Iterator` trait by one of the coroutine types
|
||||
/// generated for a `gen` construct.
|
||||
IteratorCandidate,
|
||||
|
||||
/// Implementation of an `AsyncIterator` trait by one of the coroutine types
|
||||
/// generated for a `async gen` construct.
|
||||
AsyncIteratorCandidate,
|
||||
|
||||
/// Implementation of a `Fn`-family trait by one of the anonymous
|
||||
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
||||
FnPointerCandidate {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::{TypeFlags, WithCachedTypeInfo};
|
||||
use rustc_type_ir::{ConstTy, IntoKind, TypeFlags, WithCachedTypeInfo};
|
||||
|
||||
mod int;
|
||||
mod kind;
|
||||
|
|
@ -26,6 +26,20 @@ use super::sty::ConstKind;
|
|||
#[rustc_pass_by_value]
|
||||
pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>);
|
||||
|
||||
impl<'tcx> IntoKind for Const<'tcx> {
|
||||
type Kind = ConstKind<'tcx>;
|
||||
|
||||
fn kind(self) -> ConstKind<'tcx> {
|
||||
self.kind().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstTy<TyCtxt<'tcx>> for Const<'tcx> {
|
||||
fn ty(self) -> Ty<'tcx> {
|
||||
self.ty()
|
||||
}
|
||||
}
|
||||
|
||||
/// Typed constant value.
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
|
||||
pub struct ConstData<'tcx> {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ use rustc_data_structures::profiling::SelfProfilerRef;
|
|||
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::sync::{FreezeReadGuard, Lock, WorkerLocal};
|
||||
use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, WorkerLocal};
|
||||
#[cfg(parallel_compiler)]
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::{
|
||||
DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
|
||||
|
|
@ -121,6 +123,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
|
||||
type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
|
||||
type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
|
||||
type NormalizesTo = ty::NormalizesTo<'tcx>;
|
||||
type SubtypePredicate = ty::SubtypePredicate<'tcx>;
|
||||
type CoercePredicate = ty::CoercePredicate<'tcx>;
|
||||
type ClosureKind = ty::ClosureKind;
|
||||
|
|
@ -130,6 +133,31 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
) -> (Self::Ty, ty::Mutability) {
|
||||
(ty, mutbl)
|
||||
}
|
||||
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
|
||||
self.mk_canonical_var_infos(infos)
|
||||
}
|
||||
|
||||
fn mk_bound_ty(self, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self::Ty {
|
||||
Ty::new_bound(self, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
|
||||
}
|
||||
|
||||
fn mk_bound_region(self, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self::Region {
|
||||
Region::new_bound(
|
||||
self,
|
||||
debruijn,
|
||||
ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon },
|
||||
)
|
||||
}
|
||||
|
||||
fn mk_bound_const(
|
||||
self,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
var: ty::BoundVar,
|
||||
ty: Self::Ty,
|
||||
) -> Self::Const {
|
||||
Const::new_bound(self, debruijn, var, ty)
|
||||
}
|
||||
}
|
||||
|
||||
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
|
||||
|
|
@ -552,6 +580,16 @@ pub struct TyCtxt<'tcx> {
|
|||
gcx: &'tcx GlobalCtxt<'tcx>,
|
||||
}
|
||||
|
||||
// Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution.
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl DynSend for TyCtxt<'_> {}
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl DynSync for TyCtxt<'_> {}
|
||||
fn _assert_tcx_fields() {
|
||||
sync::assert_dyn_sync::<&'_ GlobalCtxt<'_>>();
|
||||
sync::assert_dyn_send::<&'_ GlobalCtxt<'_>>();
|
||||
}
|
||||
|
||||
impl<'tcx> Deref for TyCtxt<'tcx> {
|
||||
type Target = &'tcx GlobalCtxt<'tcx>;
|
||||
#[inline(always)]
|
||||
|
|
@ -824,11 +862,16 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Coroutine))
|
||||
}
|
||||
|
||||
/// Returns `true` if the node pointed to by `def_id` is a coroutine for a gen construct.
|
||||
/// Returns `true` if the node pointed to by `def_id` is a coroutine for a `gen` construct.
|
||||
pub fn coroutine_is_gen(self, def_id: DefId) -> bool {
|
||||
matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Gen(_)))
|
||||
}
|
||||
|
||||
/// Returns `true` if the node pointed to by `def_id` is a coroutine for a `async gen` construct.
|
||||
pub fn coroutine_is_async_gen(self, def_id: DefId) -> bool {
|
||||
matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::AsyncGen(_)))
|
||||
}
|
||||
|
||||
pub fn stability(self) -> &'tcx stability::Index {
|
||||
self.stability_index(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,6 +272,10 @@ impl FlagComputation {
|
|||
self.add_const(found);
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
|
||||
self.add_alias_ty(alias);
|
||||
self.add_term(term);
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(t1, t2, _) => {
|
||||
self.add_term(t1);
|
||||
self.add_term(t2);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use smallvec::SmallVec;
|
||||
|
||||
use crate::ty::context::TyCtxt;
|
||||
use crate::ty::{self, DefId, ParamEnv, Ty};
|
||||
|
||||
|
|
@ -31,27 +33,31 @@ impl<'tcx> InhabitedPredicate<'tcx> {
|
|||
/// Returns true if the corresponding type is inhabited in the given
|
||||
/// `ParamEnv` and module
|
||||
pub fn apply(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, module_def_id: DefId) -> bool {
|
||||
let Ok(result) = self
|
||||
.apply_inner::<!>(tcx, param_env, &|id| Ok(tcx.is_descendant_of(module_def_id, id)));
|
||||
let Ok(result) = self.apply_inner::<!>(tcx, param_env, &mut Default::default(), &|id| {
|
||||
Ok(tcx.is_descendant_of(module_def_id, id))
|
||||
});
|
||||
result
|
||||
}
|
||||
|
||||
/// Same as `apply`, but returns `None` if self contains a module predicate
|
||||
pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
|
||||
self.apply_inner(tcx, param_env, &|_| Err(())).ok()
|
||||
self.apply_inner(tcx, param_env, &mut Default::default(), &|_| Err(())).ok()
|
||||
}
|
||||
|
||||
/// Same as `apply`, but `NotInModule(_)` predicates yield `false`. That is,
|
||||
/// privately uninhabited types are considered always uninhabited.
|
||||
pub fn apply_ignore_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> bool {
|
||||
let Ok(result) = self.apply_inner::<!>(tcx, param_env, &|_| Ok(true));
|
||||
let Ok(result) =
|
||||
self.apply_inner::<!>(tcx, param_env, &mut Default::default(), &|_| Ok(true));
|
||||
result
|
||||
}
|
||||
|
||||
fn apply_inner<E>(
|
||||
#[instrument(level = "debug", skip(tcx, param_env, in_module), ret)]
|
||||
fn apply_inner<E: std::fmt::Debug>(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
eval_stack: &mut SmallVec<[Ty<'tcx>; 1]>, // for cycle detection
|
||||
in_module: &impl Fn(DefId) -> Result<bool, E>,
|
||||
) -> Result<bool, E> {
|
||||
match self {
|
||||
|
|
@ -71,11 +77,25 @@ impl<'tcx> InhabitedPredicate<'tcx> {
|
|||
match normalized_pred {
|
||||
// We don't have more information than we started with, so consider inhabited.
|
||||
Self::GenericType(_) => Ok(true),
|
||||
pred => pred.apply_inner(tcx, param_env, in_module),
|
||||
pred => {
|
||||
// A type which is cyclic when monomorphized can happen here since the
|
||||
// layout error would only trigger later. See e.g. `tests/ui/sized/recursive-type-2.rs`.
|
||||
if eval_stack.contains(&t) {
|
||||
return Ok(true); // Recover; this will error later.
|
||||
}
|
||||
eval_stack.push(t);
|
||||
let ret = pred.apply_inner(tcx, param_env, eval_stack, in_module);
|
||||
eval_stack.pop();
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
|
||||
Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
|
||||
Self::And([a, b]) => {
|
||||
try_and(a, b, |x| x.apply_inner(tcx, param_env, eval_stack, in_module))
|
||||
}
|
||||
Self::Or([a, b]) => {
|
||||
try_or(a, b, |x| x.apply_inner(tcx, param_env, eval_stack, in_module))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +217,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
|
|||
|
||||
// this is basically like `f(a)? && f(b)?` but different in the case of
|
||||
// `Ok(false) && Err(_) -> Ok(false)`
|
||||
fn try_and<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> {
|
||||
fn try_and<T, E>(a: T, b: T, mut f: impl FnMut(T) -> Result<bool, E>) -> Result<bool, E> {
|
||||
let a = f(a);
|
||||
if matches!(a, Ok(false)) {
|
||||
return Ok(false);
|
||||
|
|
@ -209,7 +229,7 @@ fn try_and<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E
|
|||
}
|
||||
}
|
||||
|
||||
fn try_or<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> {
|
||||
fn try_or<T, E>(a: T, b: T, mut f: impl FnMut(T) -> Result<bool, E>) -> Result<bool, E> {
|
||||
let a = f(a);
|
||||
if matches!(a, Ok(true)) {
|
||||
return Ok(true);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ impl<'tcx> VariantDef {
|
|||
}
|
||||
|
||||
impl<'tcx> Ty<'tcx> {
|
||||
#[instrument(level = "debug", skip(tcx), ret)]
|
||||
pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
|
||||
match self.kind() {
|
||||
// For now, unions are always considered inhabited
|
||||
|
|
|
|||
|
|
@ -65,15 +65,10 @@ use std::ops::ControlFlow;
|
|||
use std::{fmt, str};
|
||||
|
||||
pub use crate::ty::diagnostics::*;
|
||||
pub use rustc_type_ir::AliasKind::*;
|
||||
pub use rustc_type_ir::ConstKind::{
|
||||
Bound as BoundCt, Error as ErrorCt, Expr as ExprCt, Infer as InferCt, Param as ParamCt,
|
||||
Placeholder as PlaceholderCt, Unevaluated, Value,
|
||||
};
|
||||
pub use rustc_type_ir::DynKind::*;
|
||||
pub use rustc_type_ir::InferTy::*;
|
||||
pub use rustc_type_ir::RegionKind::*;
|
||||
pub use rustc_type_ir::TyKind::*;
|
||||
pub use rustc_type_ir::*;
|
||||
|
||||
pub use self::binding::BindingMode;
|
||||
|
|
@ -474,6 +469,14 @@ pub struct CReaderCacheKey {
|
|||
#[rustc_pass_by_value]
|
||||
pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>);
|
||||
|
||||
impl<'tcx> IntoKind for Ty<'tcx> {
|
||||
type Kind = TyKind<'tcx>;
|
||||
|
||||
fn kind(self) -> TyKind<'tcx> {
|
||||
self.kind().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyParamRegion {
|
||||
/// Does this early bound region have a name? Early bound regions normally
|
||||
/// always have names except when using anonymous lifetimes (`'_`).
|
||||
|
|
@ -553,6 +556,10 @@ impl<'tcx> Predicate<'tcx> {
|
|||
pub fn allow_normalization(self) -> bool {
|
||||
match self.kind().skip_binder() {
|
||||
PredicateKind::Clause(ClauseKind::WellFormed(_)) => false,
|
||||
// `NormalizesTo` is only used in the new solver, so this shouldn't
|
||||
// matter. Normalizing `term` would be 'wrong' however, as it changes whether
|
||||
// `normalizes-to(<T as Trait>::Assoc, <T as Trait>::Assoc)` holds.
|
||||
PredicateKind::NormalizesTo(..) => false,
|
||||
PredicateKind::Clause(ClauseKind::Trait(_))
|
||||
| PredicateKind::Clause(ClauseKind::RegionOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
|
||||
|
|
@ -1093,6 +1100,33 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be
|
||||
/// proven by actually normalizing `alias`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct NormalizesTo<'tcx> {
|
||||
pub alias: AliasTy<'tcx>,
|
||||
pub term: Term<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> NormalizesTo<'tcx> {
|
||||
pub fn self_ty(self) -> Ty<'tcx> {
|
||||
self.alias.self_ty()
|
||||
}
|
||||
|
||||
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> NormalizesTo<'tcx> {
|
||||
Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self }
|
||||
}
|
||||
|
||||
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||
self.alias.trait_def_id(tcx)
|
||||
}
|
||||
|
||||
pub fn def_id(self) -> DefId {
|
||||
self.alias.def_id
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToPolyTraitRef<'tcx> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
|
||||
}
|
||||
|
|
@ -1274,6 +1308,12 @@ impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for NormalizesTo<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
PredicateKind::NormalizesTo(self).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Predicate<'tcx> {
|
||||
pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
|
||||
let predicate = self.kind();
|
||||
|
|
@ -1281,6 +1321,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(ClauseKind::Projection(..))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::NormalizesTo(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
|
|
@ -1300,6 +1341,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(ClauseKind::Trait(..))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::NormalizesTo(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
|
|
@ -1506,34 +1548,42 @@ pub struct Placeholder<T> {
|
|||
|
||||
pub type PlaceholderRegion = Placeholder<BoundRegion>;
|
||||
|
||||
impl rustc_type_ir::Placeholder for PlaceholderRegion {
|
||||
fn universe(&self) -> UniverseIndex {
|
||||
impl PlaceholderLike for PlaceholderRegion {
|
||||
fn universe(self) -> UniverseIndex {
|
||||
self.universe
|
||||
}
|
||||
|
||||
fn var(&self) -> BoundVar {
|
||||
fn var(self) -> BoundVar {
|
||||
self.bound.var
|
||||
}
|
||||
|
||||
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
|
||||
Placeholder { universe: ui, ..self }
|
||||
}
|
||||
|
||||
fn new(ui: UniverseIndex, var: BoundVar) -> Self {
|
||||
Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::BrAnon } }
|
||||
}
|
||||
}
|
||||
|
||||
pub type PlaceholderType = Placeholder<BoundTy>;
|
||||
|
||||
impl rustc_type_ir::Placeholder for PlaceholderType {
|
||||
fn universe(&self) -> UniverseIndex {
|
||||
impl PlaceholderLike for PlaceholderType {
|
||||
fn universe(self) -> UniverseIndex {
|
||||
self.universe
|
||||
}
|
||||
|
||||
fn var(&self) -> BoundVar {
|
||||
fn var(self) -> BoundVar {
|
||||
self.bound.var
|
||||
}
|
||||
|
||||
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
|
||||
Placeholder { universe: ui, ..self }
|
||||
}
|
||||
|
||||
fn new(ui: UniverseIndex, var: BoundVar) -> Self {
|
||||
Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
|
|
@ -1545,18 +1595,22 @@ pub struct BoundConst<'tcx> {
|
|||
|
||||
pub type PlaceholderConst = Placeholder<BoundVar>;
|
||||
|
||||
impl rustc_type_ir::Placeholder for PlaceholderConst {
|
||||
fn universe(&self) -> UniverseIndex {
|
||||
impl PlaceholderLike for PlaceholderConst {
|
||||
fn universe(self) -> UniverseIndex {
|
||||
self.universe
|
||||
}
|
||||
|
||||
fn var(&self) -> BoundVar {
|
||||
fn var(self) -> BoundVar {
|
||||
self.bound
|
||||
}
|
||||
|
||||
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
|
||||
Placeholder { universe: ui, ..self }
|
||||
}
|
||||
|
||||
fn new(ui: UniverseIndex, var: BoundVar) -> Self {
|
||||
Placeholder { universe: ui, bound: var }
|
||||
}
|
||||
}
|
||||
|
||||
/// When type checking, we use the `ParamEnv` to track
|
||||
|
|
|
|||
|
|
@ -2814,6 +2814,7 @@ define_print! {
|
|||
p!("the constant `", print(c1), "` equals `", print(c2), "`")
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => p!("ambiguous"),
|
||||
ty::PredicateKind::NormalizesTo(data) => p!(print(data)),
|
||||
ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
|
||||
}
|
||||
}
|
||||
|
|
@ -2945,6 +2946,12 @@ define_print_and_forward_display! {
|
|||
p!(print(self.term))
|
||||
}
|
||||
|
||||
ty::NormalizesTo<'tcx> {
|
||||
p!(print(self.alias), " normalizes-to ");
|
||||
cx.reset_type_limit();
|
||||
p!(print(self.term))
|
||||
}
|
||||
|
||||
ty::Term<'tcx> {
|
||||
match self.unpack() {
|
||||
ty::TermKind::Ty(ty) => p!(print(ty)),
|
||||
|
|
|
|||
|
|
@ -173,6 +173,12 @@ impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::NormalizesTo<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "NormalizesTo({:?}, {:?})", self.alias, self.term)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self.kind())
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::infer::canonical::Canonical;
|
|||
use crate::ty::visit::ValidateBoundVars;
|
||||
use crate::ty::InferTy::*;
|
||||
use crate::ty::{
|
||||
self, AdtDef, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
|
||||
self, AdtDef, Discr, IntoKind, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
|
||||
|
|
@ -1477,6 +1477,14 @@ impl ParamConst {
|
|||
#[rustc_pass_by_value]
|
||||
pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>);
|
||||
|
||||
impl<'tcx> IntoKind for Region<'tcx> {
|
||||
type Kind = RegionKind<'tcx>;
|
||||
|
||||
fn kind(self) -> RegionKind<'tcx> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Region<'tcx> {
|
||||
#[inline]
|
||||
pub fn new_early_param(
|
||||
|
|
|
|||
|
|
@ -732,6 +732,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
|
||||
match coroutine_kind {
|
||||
rustc_hir::CoroutineKind::Async(..) => "async closure",
|
||||
rustc_hir::CoroutineKind::AsyncGen(..) => "async gen closure",
|
||||
rustc_hir::CoroutineKind::Coroutine => "coroutine",
|
||||
rustc_hir::CoroutineKind::Gen(..) => "gen closure",
|
||||
}
|
||||
|
|
@ -752,6 +753,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
|
||||
match coroutine_kind {
|
||||
rustc_hir::CoroutineKind::Async(..) => "an",
|
||||
rustc_hir::CoroutineKind::AsyncGen(..) => "an",
|
||||
rustc_hir::CoroutineKind::Coroutine => "a",
|
||||
rustc_hir::CoroutineKind::Gen(..) => "a",
|
||||
}
|
||||
|
|
@ -781,9 +783,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
|
||||
pub fn expected_const_effect_param_for_body(self, def_id: LocalDefId) -> ty::Const<'tcx> {
|
||||
// if the callee does have the param, we need to equate the param to some const
|
||||
// value no matter whether the effects feature is enabled in the local crate,
|
||||
// because inference will fail if we don't.
|
||||
// FIXME(effects): This is suspicious and should probably not be done,
|
||||
// especially now that we enforce host effects and then properly handle
|
||||
// effect vars during fallback.
|
||||
let mut host_always_on =
|
||||
!self.features().effects || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ rustc_index = { path = "../rustc_index" }
|
|||
rustc_infer = { path = "../rustc_infer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_pattern_analysis = { path = "../rustc_pattern_analysis" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
|
|
|
|||
|
|
@ -237,15 +237,6 @@ mir_build_non_const_path = runtime values cannot be referenced in patterns
|
|||
mir_build_non_exhaustive_match_all_arms_guarded =
|
||||
match arms with guards don't count towards exhaustivity
|
||||
|
||||
mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
|
||||
.help = ensure that all variants are matched explicitly by adding the suggested match arms
|
||||
.note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
|
||||
|
||||
mir_build_non_exhaustive_omitted_pattern_lint_on_arm = the lint level must be set on the whole match
|
||||
.help = it no longer has any effect to set the lint level on an individual match arm
|
||||
.label = remove this attribute
|
||||
.suggestion = set the lint level on the whole match
|
||||
|
||||
mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
|
||||
.def_note = `{$peeled_ty}` defined here
|
||||
.type_note = the matched value is of type `{$ty}`
|
||||
|
|
@ -260,10 +251,6 @@ mir_build_non_partial_eq_match =
|
|||
mir_build_nontrivial_structural_match =
|
||||
to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
|
||||
mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints
|
||||
.range = ... with this range
|
||||
.note = you likely meant to write mutually exclusive ranges
|
||||
|
||||
mir_build_pattern_not_covered = refutable pattern in {$origin}
|
||||
.pattern_ty = the matched value is of type `{$pattern_ty}`
|
||||
|
||||
|
|
@ -317,13 +304,6 @@ mir_build_unconditional_recursion = function cannot return without recursing
|
|||
|
||||
mir_build_unconditional_recursion_call_site_label = recursive call site
|
||||
|
||||
mir_build_uncovered = {$count ->
|
||||
[1] pattern `{$witness_1}`
|
||||
[2] patterns `{$witness_1}` and `{$witness_2}`
|
||||
[3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
|
||||
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
|
||||
} not covered
|
||||
|
||||
mir_build_union_field_requires_unsafe =
|
||||
access to union field is unsafe and requires unsafe block
|
||||
.note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
|
|
|
|||
|
|
@ -13,32 +13,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
ast_block: BlockId,
|
||||
source_info: SourceInfo,
|
||||
) -> BlockAnd<()> {
|
||||
let Block {
|
||||
region_scope,
|
||||
opt_destruction_scope,
|
||||
span,
|
||||
ref stmts,
|
||||
expr,
|
||||
targeted_by_break,
|
||||
safety_mode,
|
||||
} = self.thir[ast_block];
|
||||
let Block { region_scope, span, ref stmts, expr, targeted_by_break, safety_mode } =
|
||||
self.thir[ast_block];
|
||||
let expr = expr.map(|expr| &self.thir[expr]);
|
||||
self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
|
||||
this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
|
||||
if targeted_by_break {
|
||||
this.in_breakable_scope(None, destination, span, |this| {
|
||||
Some(this.ast_block_stmts(
|
||||
destination,
|
||||
block,
|
||||
span,
|
||||
stmts,
|
||||
expr,
|
||||
safety_mode,
|
||||
region_scope,
|
||||
))
|
||||
})
|
||||
} else {
|
||||
this.ast_block_stmts(
|
||||
self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
|
||||
if targeted_by_break {
|
||||
this.in_breakable_scope(None, destination, span, |this| {
|
||||
Some(this.ast_block_stmts(
|
||||
destination,
|
||||
block,
|
||||
span,
|
||||
|
|
@ -46,9 +27,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
expr,
|
||||
safety_mode,
|
||||
region_scope,
|
||||
)
|
||||
}
|
||||
})
|
||||
))
|
||||
})
|
||||
} else {
|
||||
this.ast_block_stmts(
|
||||
destination,
|
||||
block,
|
||||
span,
|
||||
stmts,
|
||||
expr,
|
||||
safety_mode,
|
||||
region_scope,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -92,20 +83,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
let source_info = this.source_info(span);
|
||||
for stmt in stmts {
|
||||
let Stmt { ref kind, opt_destruction_scope } = this.thir[*stmt];
|
||||
let Stmt { ref kind } = this.thir[*stmt];
|
||||
match kind {
|
||||
StmtKind::Expr { scope, expr } => {
|
||||
this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
|
||||
let si = (*scope, source_info);
|
||||
unpack!(
|
||||
block = this.in_opt_scope(
|
||||
opt_destruction_scope.map(|de| (de, source_info)),
|
||||
|this| {
|
||||
let si = (*scope, source_info);
|
||||
this.in_scope(si, LintLevel::Inherited, |this| {
|
||||
this.stmt_expr(block, &this.thir[*expr], Some(*scope))
|
||||
})
|
||||
}
|
||||
)
|
||||
block = this.in_scope(si, LintLevel::Inherited, |this| {
|
||||
this.stmt_expr(block, &this.thir[*expr], Some(*scope))
|
||||
})
|
||||
);
|
||||
}
|
||||
StmtKind::Let {
|
||||
|
|
@ -221,43 +207,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
let init = &this.thir[*initializer];
|
||||
let initializer_span = init.span;
|
||||
let scope = (*init_scope, source_info);
|
||||
let failure = unpack!(
|
||||
block = this.in_opt_scope(
|
||||
opt_destruction_scope.map(|de| (de, source_info)),
|
||||
|this| {
|
||||
let scope = (*init_scope, source_info);
|
||||
this.in_scope(scope, *lint_level, |this| {
|
||||
this.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
None,
|
||||
Some((Some(&destination), initializer_span)),
|
||||
);
|
||||
this.visit_primary_bindings(
|
||||
pattern,
|
||||
UserTypeProjections::none(),
|
||||
&mut |this, _, _, _, node, span, _, _| {
|
||||
this.storage_live_binding(
|
||||
block,
|
||||
node,
|
||||
span,
|
||||
OutsideGuard,
|
||||
true,
|
||||
);
|
||||
},
|
||||
);
|
||||
this.ast_let_else(
|
||||
block = this.in_scope(scope, *lint_level, |this| {
|
||||
this.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
None,
|
||||
Some((Some(&destination), initializer_span)),
|
||||
);
|
||||
this.visit_primary_bindings(
|
||||
pattern,
|
||||
UserTypeProjections::none(),
|
||||
&mut |this, _, _, _, node, span, _, _| {
|
||||
this.storage_live_binding(
|
||||
block,
|
||||
init,
|
||||
initializer_span,
|
||||
*else_block,
|
||||
&last_remainder_scope,
|
||||
pattern,
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
node,
|
||||
span,
|
||||
OutsideGuard,
|
||||
true,
|
||||
);
|
||||
},
|
||||
);
|
||||
this.ast_let_else(
|
||||
block,
|
||||
init,
|
||||
initializer_span,
|
||||
*else_block,
|
||||
&last_remainder_scope,
|
||||
pattern,
|
||||
)
|
||||
})
|
||||
);
|
||||
this.cfg.goto(failure, source_info, failure_entry);
|
||||
|
||||
|
|
@ -298,25 +279,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
if let Some(init) = initializer {
|
||||
let init = &this.thir[*init];
|
||||
let initializer_span = init.span;
|
||||
let scope = (*init_scope, source_info);
|
||||
|
||||
unpack!(
|
||||
block = this.in_opt_scope(
|
||||
opt_destruction_scope.map(|de| (de, source_info)),
|
||||
|this| {
|
||||
let scope = (*init_scope, source_info);
|
||||
this.in_scope(scope, *lint_level, |this| {
|
||||
this.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
None,
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
this.expr_into_pattern(block, pattern, init)
|
||||
// irrefutable pattern
|
||||
})
|
||||
},
|
||||
)
|
||||
block = this.in_scope(scope, *lint_level, |this| {
|
||||
this.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
None,
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
this.expr_into_pattern(block, &pattern, init)
|
||||
// irrefutable pattern
|
||||
})
|
||||
)
|
||||
} else {
|
||||
let scope = (*init_scope, source_info);
|
||||
|
|
|
|||
|
|
@ -101,6 +101,19 @@ impl<'tcx> CFG<'tcx> {
|
|||
self.push(block, stmt);
|
||||
}
|
||||
|
||||
/// Adds a dummy statement whose only role is to associate a span with its
|
||||
/// enclosing block for the purposes of coverage instrumentation.
|
||||
///
|
||||
/// This results in more accurate coverage reports for certain kinds of
|
||||
/// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR.
|
||||
pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) {
|
||||
let kind = StatementKind::Coverage(Box::new(Coverage {
|
||||
kind: coverage::CoverageKind::SpanMarker,
|
||||
}));
|
||||
let stmt = Statement { source_info, kind };
|
||||
self.push(block, stmt);
|
||||
}
|
||||
|
||||
pub(crate) fn terminate(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
|
|
|
|||
|
|
@ -90,6 +90,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let local_scope = this.local_scope();
|
||||
let (success_block, failure_block) =
|
||||
this.in_if_then_scope(local_scope, expr_span, |this| {
|
||||
// Help out coverage instrumentation by injecting a dummy statement with
|
||||
// the original condition's span (including `!`). This fixes #115468.
|
||||
if this.tcx.sess.instrument_coverage() {
|
||||
this.cfg.push_coverage_span_marker(block, this.source_info(expr_span));
|
||||
}
|
||||
this.then_else_break(
|
||||
block,
|
||||
&this.thir[arg],
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ use rustc_index::{IndexSlice, IndexVec};
|
|||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::{Expr, LintLevel};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
|
|
@ -537,27 +536,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
(then_block, else_block)
|
||||
}
|
||||
|
||||
pub(crate) fn in_opt_scope<F, R>(
|
||||
&mut self,
|
||||
opt_scope: Option<(region::Scope, SourceInfo)>,
|
||||
f: F,
|
||||
) -> BlockAnd<R>
|
||||
where
|
||||
F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
|
||||
{
|
||||
debug!("in_opt_scope(opt_scope={:?})", opt_scope);
|
||||
if let Some(region_scope) = opt_scope {
|
||||
self.push_scope(region_scope);
|
||||
}
|
||||
let mut block;
|
||||
let rv = unpack!(block = f(self));
|
||||
if let Some(region_scope) = opt_scope {
|
||||
unpack!(block = self.pop_scope(region_scope, block));
|
||||
}
|
||||
debug!("in_scope: exiting opt_scope={:?} block={:?}", opt_scope, block);
|
||||
block.and(rv)
|
||||
}
|
||||
|
||||
/// Convenience wrapper that pushes a scope and then executes `f`
|
||||
/// to build its contents, popping the scope afterwards.
|
||||
#[instrument(skip(self, f), level = "debug")]
|
||||
|
|
@ -660,14 +638,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
(None, Some(_)) => {
|
||||
panic!("`return`, `become` and `break` with value and must have a destination")
|
||||
}
|
||||
(None, None) if self.tcx.sess.instrument_coverage() => {
|
||||
// Unlike `break` and `return`, which push an `Assign` statement to MIR, from which
|
||||
// a Coverage code region can be generated, `continue` needs no `Assign`; but
|
||||
// without one, the `InstrumentCoverage` MIR pass cannot generate a code region for
|
||||
// `continue`. Coverage will be missing unless we add a dummy `Assign` to MIR.
|
||||
self.add_dummy_assignment(span, block, source_info);
|
||||
(None, None) => {
|
||||
if self.tcx.sess.instrument_coverage() {
|
||||
// Normally we wouldn't build any MIR in this case, but that makes it
|
||||
// harder for coverage instrumentation to extract a relevant span for
|
||||
// `continue` expressions. So here we inject a dummy statement with the
|
||||
// desired span.
|
||||
self.cfg.push_coverage_span_marker(block, source_info);
|
||||
}
|
||||
}
|
||||
(None, None) => {}
|
||||
}
|
||||
|
||||
let region_scope = self.scopes.breakable_scopes[break_index].region_scope;
|
||||
|
|
@ -723,14 +702,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.cfg.terminate(block, source_info, TerminatorKind::UnwindResume);
|
||||
}
|
||||
|
||||
// Add a dummy `Assign` statement to the CFG, with the span for the source code's `continue`
|
||||
// statement.
|
||||
fn add_dummy_assignment(&mut self, span: Span, block: BasicBlock, source_info: SourceInfo) {
|
||||
let local_decl = LocalDecl::new(Ty::new_unit(self.tcx), span);
|
||||
let temp_place = Place::from(self.local_decls.push(local_decl));
|
||||
self.cfg.push_assign_unit(block, source_info, temp_place, self.tcx);
|
||||
}
|
||||
|
||||
fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
|
||||
// If we are emitting a `drop` statement, we need to have the cached
|
||||
// diverge cleanup pads ready in case that drop panics.
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
use crate::{
|
||||
fluent_generated as fluent,
|
||||
thir::pattern::{deconstruct_pat::WitnessPat, MatchCheckCtxt},
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
use rustc_errors::DiagnosticArgValue;
|
||||
use rustc_errors::{
|
||||
error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::thir::Pat;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_pattern_analysis::{cx::MatchCheckCtxt, errors::Uncovered};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
@ -812,94 +809,6 @@ pub struct NonPartialEqMatch<'tcx> {
|
|||
pub non_peq_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_overlapping_range_endpoints)]
|
||||
#[note]
|
||||
pub struct OverlappingRangeEndpoints<'tcx> {
|
||||
#[label(mir_build_range)]
|
||||
pub range: Span,
|
||||
#[subdiagnostic]
|
||||
pub overlap: Vec<Overlap<'tcx>>,
|
||||
}
|
||||
|
||||
pub struct Overlap<'tcx> {
|
||||
pub span: Span,
|
||||
pub range: Pat<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> AddToDiagnostic for Overlap<'tcx> {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
let Overlap { span, range } = self;
|
||||
|
||||
// FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
|
||||
// does not support `#[subdiagnostic(eager)]`...
|
||||
let message = format!("this range overlaps on `{range}`...");
|
||||
diag.span_label(span, message);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_non_exhaustive_omitted_pattern)]
|
||||
#[help]
|
||||
#[note]
|
||||
pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
|
||||
pub scrut_ty: Ty<'tcx>,
|
||||
#[subdiagnostic]
|
||||
pub uncovered: Uncovered<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_non_exhaustive_omitted_pattern_lint_on_arm)]
|
||||
#[help]
|
||||
pub(crate) struct NonExhaustiveOmittedPatternLintOnArm {
|
||||
#[label]
|
||||
pub lint_span: Span,
|
||||
#[suggestion(code = "#[{lint_level}({lint_name})]\n", applicability = "maybe-incorrect")]
|
||||
pub suggest_lint_on_match: Option<Span>,
|
||||
pub lint_level: &'static str,
|
||||
pub lint_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(mir_build_uncovered)]
|
||||
pub(crate) struct Uncovered<'tcx> {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
count: usize,
|
||||
witness_1: Pat<'tcx>,
|
||||
witness_2: Pat<'tcx>,
|
||||
witness_3: Pat<'tcx>,
|
||||
remainder: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> Uncovered<'tcx> {
|
||||
pub fn new<'p>(
|
||||
span: Span,
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
witnesses: Vec<WitnessPat<'tcx>>,
|
||||
) -> Self {
|
||||
let witness_1 = witnesses.get(0).unwrap().to_diagnostic_pat(cx);
|
||||
Self {
|
||||
span,
|
||||
count: witnesses.len(),
|
||||
// Substitute dummy values if witnesses is smaller than 3. These will never be read.
|
||||
witness_2: witnesses
|
||||
.get(1)
|
||||
.map(|w| w.to_diagnostic_pat(cx))
|
||||
.unwrap_or_else(|| witness_1.clone()),
|
||||
witness_3: witnesses
|
||||
.get(2)
|
||||
.map(|w| w.to_diagnostic_pat(cx))
|
||||
.unwrap_or_else(|| witness_1.clone()),
|
||||
witness_1,
|
||||
remainder: witnesses.len().saturating_sub(3),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_pattern_not_covered, code = "E0005")]
|
||||
pub(crate) struct PatternNotCovered<'s, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -13,15 +13,12 @@ impl<'tcx> Cx<'tcx> {
|
|||
// We have to eagerly lower the "spine" of the statements
|
||||
// in order to get the lexical scoping correctly.
|
||||
let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts);
|
||||
let opt_destruction_scope =
|
||||
self.region_scope_tree.opt_destruction_scope(block.hir_id.local_id);
|
||||
let block = Block {
|
||||
targeted_by_break: block.targeted_by_break,
|
||||
region_scope: region::Scope {
|
||||
id: block.hir_id.local_id,
|
||||
data: region::ScopeData::Node,
|
||||
},
|
||||
opt_destruction_scope,
|
||||
span: block.span,
|
||||
stmts,
|
||||
expr: block.expr.map(|expr| self.mirror_expr(expr)),
|
||||
|
|
@ -49,7 +46,6 @@ impl<'tcx> Cx<'tcx> {
|
|||
.enumerate()
|
||||
.filter_map(|(index, stmt)| {
|
||||
let hir_id = stmt.hir_id;
|
||||
let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
|
||||
match stmt.kind {
|
||||
hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => {
|
||||
let stmt = Stmt {
|
||||
|
|
@ -60,7 +56,6 @@ impl<'tcx> Cx<'tcx> {
|
|||
},
|
||||
expr: self.mirror_expr(expr),
|
||||
},
|
||||
opt_destruction_scope: opt_dxn_ext,
|
||||
};
|
||||
Some(self.thir.stmts.push(stmt))
|
||||
}
|
||||
|
|
@ -122,7 +117,6 @@ impl<'tcx> Cx<'tcx> {
|
|||
lint_level: LintLevel::Explicit(local.hir_id),
|
||||
span,
|
||||
},
|
||||
opt_destruction_scope: opt_dxn_ext,
|
||||
};
|
||||
Some(self.thir.stmts.push(stmt))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ impl<'tcx> Cx<'tcx> {
|
|||
|
||||
trace!(?expr.ty, "after adjustments");
|
||||
|
||||
// Next, wrap this up in the expr's scope.
|
||||
// Finally, wrap this up in the expr's scope.
|
||||
expr = Expr {
|
||||
temp_lifetime: expr.temp_lifetime,
|
||||
ty: expr.ty,
|
||||
|
|
@ -66,22 +66,6 @@ impl<'tcx> Cx<'tcx> {
|
|||
},
|
||||
};
|
||||
|
||||
// Finally, create a destruction scope, if any.
|
||||
if let Some(region_scope) =
|
||||
self.region_scope_tree.opt_destruction_scope(hir_expr.hir_id.local_id)
|
||||
{
|
||||
expr = Expr {
|
||||
temp_lifetime: expr.temp_lifetime,
|
||||
ty: expr.ty,
|
||||
span: hir_expr.span,
|
||||
kind: ExprKind::Scope {
|
||||
region_scope,
|
||||
value: self.thir.exprs.push(expr),
|
||||
lint_level: LintLevel::Inherited,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// OK, all done!
|
||||
self.thir.exprs.push(expr)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use super::deconstruct_pat::{Constructor, DeconstructedPat, WitnessPat};
|
||||
use super::usefulness::{
|
||||
compute_match_usefulness, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport,
|
||||
};
|
||||
use rustc_pattern_analysis::constructor::Constructor;
|
||||
use rustc_pattern_analysis::cx::MatchCheckCtxt;
|
||||
use rustc_pattern_analysis::errors::Uncovered;
|
||||
use rustc_pattern_analysis::pat::{DeconstructedPat, WitnessPat};
|
||||
use rustc_pattern_analysis::usefulness::{Usefulness, UsefulnessReport};
|
||||
use rustc_pattern_analysis::{analyze_match, MatchArm};
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
|
|
@ -42,7 +44,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err
|
|||
|
||||
for param in thir.params.iter() {
|
||||
if let Some(box ref pattern) = param.pat {
|
||||
visitor.check_binding_is_irrefutable(pattern, "function argument", None);
|
||||
visitor.check_binding_is_irrefutable(pattern, "function argument", None, None);
|
||||
}
|
||||
}
|
||||
visitor.error
|
||||
|
|
@ -254,10 +256,11 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
|
|||
self.with_lint_level(lint_level, |this| this.visit_land_rhs(&this.thir[value]))
|
||||
}
|
||||
ExprKind::Let { box ref pat, expr } => {
|
||||
let expr = &self.thir()[expr];
|
||||
self.with_let_source(LetSource::None, |this| {
|
||||
this.visit_expr(&this.thir()[expr]);
|
||||
this.visit_expr(expr);
|
||||
});
|
||||
Ok(Some((ex.span, self.is_let_irrefutable(pat)?)))
|
||||
Ok(Some((ex.span, self.is_let_irrefutable(pat, Some(expr))?)))
|
||||
}
|
||||
_ => {
|
||||
self.with_let_source(LetSource::None, |this| {
|
||||
|
|
@ -283,39 +286,118 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
|
|||
check_borrow_conflicts_in_at_patterns(self, pat);
|
||||
check_for_bindings_named_same_as_variants(self, pat, refutable);
|
||||
});
|
||||
Ok(cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, pat)))
|
||||
Ok(cx.pattern_arena.alloc(cx.lower_pat(pat)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Inspects the match scrutinee expression to determine whether the place it evaluates to may
|
||||
/// hold invalid data.
|
||||
fn is_known_valid_scrutinee(&self, scrutinee: &Expr<'tcx>) -> bool {
|
||||
use ExprKind::*;
|
||||
match &scrutinee.kind {
|
||||
// Both pointers and references can validly point to a place with invalid data.
|
||||
Deref { .. } => false,
|
||||
// Inherit validity of the parent place, unless the parent is an union.
|
||||
Field { lhs, .. } => {
|
||||
let lhs = &self.thir()[*lhs];
|
||||
match lhs.ty.kind() {
|
||||
ty::Adt(def, _) if def.is_union() => false,
|
||||
_ => self.is_known_valid_scrutinee(lhs),
|
||||
}
|
||||
}
|
||||
// Essentially a field access.
|
||||
Index { lhs, .. } => {
|
||||
let lhs = &self.thir()[*lhs];
|
||||
self.is_known_valid_scrutinee(lhs)
|
||||
}
|
||||
|
||||
// No-op.
|
||||
Scope { value, .. } => self.is_known_valid_scrutinee(&self.thir()[*value]),
|
||||
|
||||
// Casts don't cause a load.
|
||||
NeverToAny { source }
|
||||
| Cast { source }
|
||||
| Use { source }
|
||||
| PointerCoercion { source, .. }
|
||||
| PlaceTypeAscription { source, .. }
|
||||
| ValueTypeAscription { source, .. } => {
|
||||
self.is_known_valid_scrutinee(&self.thir()[*source])
|
||||
}
|
||||
|
||||
// These diverge.
|
||||
Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true,
|
||||
|
||||
// These are statements that evaluate to `()`.
|
||||
Assign { .. } | AssignOp { .. } | InlineAsm { .. } | Let { .. } => true,
|
||||
|
||||
// These evaluate to a value.
|
||||
AddressOf { .. }
|
||||
| Adt { .. }
|
||||
| Array { .. }
|
||||
| Binary { .. }
|
||||
| Block { .. }
|
||||
| Borrow { .. }
|
||||
| Box { .. }
|
||||
| Call { .. }
|
||||
| Closure { .. }
|
||||
| ConstBlock { .. }
|
||||
| ConstParam { .. }
|
||||
| If { .. }
|
||||
| Literal { .. }
|
||||
| LogicalOp { .. }
|
||||
| Loop { .. }
|
||||
| Match { .. }
|
||||
| NamedConst { .. }
|
||||
| NonHirLiteral { .. }
|
||||
| OffsetOf { .. }
|
||||
| Repeat { .. }
|
||||
| StaticRef { .. }
|
||||
| ThreadLocalRef { .. }
|
||||
| Tuple { .. }
|
||||
| Unary { .. }
|
||||
| UpvarRef { .. }
|
||||
| VarRef { .. }
|
||||
| ZstLiteral { .. }
|
||||
| Yield { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_cx(
|
||||
&self,
|
||||
refutability: RefutableFlag,
|
||||
match_span: Option<Span>,
|
||||
whole_match_span: Option<Span>,
|
||||
scrutinee: Option<&Expr<'tcx>>,
|
||||
scrut_span: Span,
|
||||
) -> MatchCheckCtxt<'p, 'tcx> {
|
||||
let refutable = match refutability {
|
||||
Irrefutable => false,
|
||||
Refutable => true,
|
||||
};
|
||||
// If we don't have a scrutinee we're either a function parameter or a `let x;`. Both cases
|
||||
// require validity.
|
||||
let known_valid_scrutinee =
|
||||
scrutinee.map(|scrut| self.is_known_valid_scrutinee(scrut)).unwrap_or(true);
|
||||
MatchCheckCtxt {
|
||||
tcx: self.tcx,
|
||||
param_env: self.param_env,
|
||||
module: self.tcx.parent_module(self.lint_level).to_def_id(),
|
||||
pattern_arena: self.pattern_arena,
|
||||
match_lint_level: self.lint_level,
|
||||
match_span,
|
||||
whole_match_span,
|
||||
scrut_span,
|
||||
refutable,
|
||||
known_valid_scrutinee,
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn check_let(&mut self, pat: &Pat<'tcx>, scrutinee: Option<ExprId>, span: Span) {
|
||||
assert!(self.let_source != LetSource::None);
|
||||
let scrut = scrutinee.map(|id| &self.thir[id]);
|
||||
if let LetSource::PlainLet = self.let_source {
|
||||
self.check_binding_is_irrefutable(pat, "local binding", Some(span))
|
||||
self.check_binding_is_irrefutable(pat, "local binding", scrut, Some(span))
|
||||
} else {
|
||||
let Ok(refutability) = self.is_let_irrefutable(pat) else { return };
|
||||
let Ok(refutability) = self.is_let_irrefutable(pat, scrut) else { return };
|
||||
if matches!(refutability, Irrefutable) {
|
||||
report_irrefutable_let_patterns(
|
||||
self.tcx,
|
||||
|
|
@ -336,7 +418,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
|
|||
expr_span: Span,
|
||||
) {
|
||||
let scrut = &self.thir[scrut];
|
||||
let cx = self.new_cx(Refutable, Some(expr_span), scrut.span);
|
||||
let cx = self.new_cx(Refutable, Some(expr_span), Some(scrut), scrut.span);
|
||||
|
||||
let mut tarms = Vec::with_capacity(arms.len());
|
||||
for &arm in arms {
|
||||
|
|
@ -353,7 +435,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
|
|||
}
|
||||
|
||||
let scrut_ty = scrut.ty;
|
||||
let report = compute_match_usefulness(&cx, &tarms, scrut_ty);
|
||||
let report = analyze_match(&cx, &tarms, scrut_ty);
|
||||
|
||||
match source {
|
||||
// Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
|
||||
|
|
@ -377,7 +459,12 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
|
|||
debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop));
|
||||
let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() };
|
||||
let [pat_field] = &subpatterns[..] else { bug!() };
|
||||
self.check_binding_is_irrefutable(&pat_field.pattern, "`for` loop binding", None);
|
||||
self.check_binding_is_irrefutable(
|
||||
&pat_field.pattern,
|
||||
"`for` loop binding",
|
||||
None,
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
self.error = Err(report_non_exhaustive_match(
|
||||
&cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span,
|
||||
|
|
@ -457,16 +544,21 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
|
|||
&mut self,
|
||||
pat: &Pat<'tcx>,
|
||||
refutability: RefutableFlag,
|
||||
scrut: Option<&Expr<'tcx>>,
|
||||
) -> Result<(MatchCheckCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> {
|
||||
let cx = self.new_cx(refutability, None, pat.span);
|
||||
let cx = self.new_cx(refutability, None, scrut, pat.span);
|
||||
let pat = self.lower_pattern(&cx, pat)?;
|
||||
let arms = [MatchArm { pat, hir_id: self.lint_level, has_guard: false }];
|
||||
let report = compute_match_usefulness(&cx, &arms, pat.ty());
|
||||
let report = analyze_match(&cx, &arms, pat.ty());
|
||||
Ok((cx, report))
|
||||
}
|
||||
|
||||
fn is_let_irrefutable(&mut self, pat: &Pat<'tcx>) -> Result<RefutableFlag, ErrorGuaranteed> {
|
||||
let (cx, report) = self.analyze_binding(pat, Refutable)?;
|
||||
fn is_let_irrefutable(
|
||||
&mut self,
|
||||
pat: &Pat<'tcx>,
|
||||
scrut: Option<&Expr<'tcx>>,
|
||||
) -> Result<RefutableFlag, ErrorGuaranteed> {
|
||||
let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?;
|
||||
// Report if the pattern is unreachable, which can only occur when the type is uninhabited.
|
||||
// This also reports unreachable sub-patterns.
|
||||
report_arm_reachability(&cx, &report);
|
||||
|
|
@ -476,10 +568,16 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn check_binding_is_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
|
||||
fn check_binding_is_irrefutable(
|
||||
&mut self,
|
||||
pat: &Pat<'tcx>,
|
||||
origin: &str,
|
||||
scrut: Option<&Expr<'tcx>>,
|
||||
sp: Option<Span>,
|
||||
) {
|
||||
let pattern_ty = pat.ty;
|
||||
|
||||
let Ok((cx, report)) = self.analyze_binding(pat, Irrefutable) else { return };
|
||||
let Ok((cx, report)) = self.analyze_binding(pat, Irrefutable, scrut) else { return };
|
||||
let witnesses = report.non_exhaustiveness_witnesses;
|
||||
if witnesses.is_empty() {
|
||||
// The pattern is irrefutable.
|
||||
|
|
@ -749,18 +847,18 @@ fn report_arm_reachability<'p, 'tcx>(
|
|||
);
|
||||
};
|
||||
|
||||
use Reachability::*;
|
||||
use Usefulness::*;
|
||||
let mut catchall = None;
|
||||
for (arm, is_useful) in report.arm_usefulness.iter() {
|
||||
match is_useful {
|
||||
Unreachable => report_unreachable_pattern(arm.pat.span(), arm.hir_id, catchall),
|
||||
Reachable(unreachables) if unreachables.is_empty() => {}
|
||||
// The arm is reachable, but contains unreachable subpatterns (from or-patterns).
|
||||
Reachable(unreachables) => {
|
||||
let mut unreachables = unreachables.clone();
|
||||
Redundant => report_unreachable_pattern(arm.pat.span(), arm.hir_id, catchall),
|
||||
Useful(redundant_spans) if redundant_spans.is_empty() => {}
|
||||
// The arm is reachable, but contains redundant subpatterns (from or-patterns).
|
||||
Useful(redundant_spans) => {
|
||||
let mut redundant_spans = redundant_spans.clone();
|
||||
// Emit lints in the order in which they occur in the file.
|
||||
unreachables.sort_unstable();
|
||||
for span in unreachables {
|
||||
redundant_spans.sort_unstable();
|
||||
for span in redundant_spans {
|
||||
report_unreachable_pattern(span, arm.hir_id, None);
|
||||
}
|
||||
}
|
||||
|
|
@ -828,7 +926,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
|
|||
pattern = if witnesses.len() < 4 {
|
||||
witnesses
|
||||
.iter()
|
||||
.map(|witness| witness.to_diagnostic_pat(cx).to_string())
|
||||
.map(|witness| cx.hoist_witness_pat(witness).to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(" | ")
|
||||
} else {
|
||||
|
|
@ -852,7 +950,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
|
|||
if !is_empty_match {
|
||||
let mut non_exhaustive_tys = FxHashSet::default();
|
||||
// Look at the first witness.
|
||||
collect_non_exhaustive_tys(cx.tcx, &witnesses[0], &mut non_exhaustive_tys);
|
||||
collect_non_exhaustive_tys(cx, &witnesses[0], &mut non_exhaustive_tys);
|
||||
|
||||
for ty in non_exhaustive_tys {
|
||||
if ty.is_ptr_sized_integral() {
|
||||
|
|
@ -987,13 +1085,13 @@ fn joined_uncovered_patterns<'p, 'tcx>(
|
|||
witnesses: &[WitnessPat<'tcx>],
|
||||
) -> String {
|
||||
const LIMIT: usize = 3;
|
||||
let pat_to_str = |pat: &WitnessPat<'tcx>| pat.to_diagnostic_pat(cx).to_string();
|
||||
let pat_to_str = |pat: &WitnessPat<'tcx>| cx.hoist_witness_pat(pat).to_string();
|
||||
match witnesses {
|
||||
[] => bug!(),
|
||||
[witness] => format!("`{}`", witness.to_diagnostic_pat(cx)),
|
||||
[witness] => format!("`{}`", cx.hoist_witness_pat(witness)),
|
||||
[head @ .., tail] if head.len() < LIMIT => {
|
||||
let head: Vec<_> = head.iter().map(pat_to_str).collect();
|
||||
format!("`{}` and `{}`", head.join("`, `"), tail.to_diagnostic_pat(cx))
|
||||
format!("`{}` and `{}`", head.join("`, `"), cx.hoist_witness_pat(tail))
|
||||
}
|
||||
_ => {
|
||||
let (head, tail) = witnesses.split_at(LIMIT);
|
||||
|
|
@ -1004,7 +1102,7 @@ fn joined_uncovered_patterns<'p, 'tcx>(
|
|||
}
|
||||
|
||||
fn collect_non_exhaustive_tys<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cx: &MatchCheckCtxt<'_, 'tcx>,
|
||||
pat: &WitnessPat<'tcx>,
|
||||
non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
|
||||
) {
|
||||
|
|
@ -1012,13 +1110,13 @@ fn collect_non_exhaustive_tys<'tcx>(
|
|||
non_exhaustive_tys.insert(pat.ty());
|
||||
}
|
||||
if let Constructor::IntRange(range) = pat.ctor() {
|
||||
if range.is_beyond_boundaries(pat.ty(), tcx) {
|
||||
if cx.is_range_beyond_boundaries(range, pat.ty()) {
|
||||
// The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`.
|
||||
non_exhaustive_tys.insert(pat.ty());
|
||||
}
|
||||
}
|
||||
pat.iter_fields()
|
||||
.for_each(|field_pat| collect_non_exhaustive_tys(tcx, field_pat, non_exhaustive_tys))
|
||||
.for_each(|field_pat| collect_non_exhaustive_tys(cx, field_pat, non_exhaustive_tys))
|
||||
}
|
||||
|
||||
fn report_adt_defined_here<'tcx>(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,11 +2,8 @@
|
|||
|
||||
mod check_match;
|
||||
mod const_to_pat;
|
||||
pub(crate) mod deconstruct_pat;
|
||||
mod usefulness;
|
||||
|
||||
pub(crate) use self::check_match::check_match;
|
||||
pub(crate) use self::usefulness::MatchCheckCtxt;
|
||||
|
||||
use crate::errors::*;
|
||||
use crate::thir::util::UserAnnotatedTyHelpers;
|
||||
|
|
|
|||
|
|
@ -91,23 +91,11 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn print_block(&mut self, block_id: BlockId, depth_lvl: usize) {
|
||||
let Block {
|
||||
targeted_by_break,
|
||||
opt_destruction_scope,
|
||||
span,
|
||||
region_scope,
|
||||
stmts,
|
||||
expr,
|
||||
safety_mode,
|
||||
} = &self.thir.blocks[block_id];
|
||||
let Block { targeted_by_break, span, region_scope, stmts, expr, safety_mode } =
|
||||
&self.thir.blocks[block_id];
|
||||
|
||||
print_indented!(self, "Block {", depth_lvl);
|
||||
print_indented!(self, format!("targeted_by_break: {}", targeted_by_break), depth_lvl + 1);
|
||||
print_indented!(
|
||||
self,
|
||||
format!("opt_destruction_scope: {:?}", opt_destruction_scope),
|
||||
depth_lvl + 1
|
||||
);
|
||||
print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
|
||||
print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
|
||||
print_indented!(self, format!("safety_mode: {:?}", safety_mode), depth_lvl + 1);
|
||||
|
|
@ -133,14 +121,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn print_stmt(&mut self, stmt_id: StmtId, depth_lvl: usize) {
|
||||
let Stmt { kind, opt_destruction_scope } = &self.thir.stmts[stmt_id];
|
||||
let Stmt { kind } = &self.thir.stmts[stmt_id];
|
||||
|
||||
print_indented!(self, "Stmt {", depth_lvl);
|
||||
print_indented!(
|
||||
self,
|
||||
format!("opt_destruction_scope: {:?}", opt_destruction_scope),
|
||||
depth_lvl + 1
|
||||
);
|
||||
|
||||
match kind {
|
||||
StmtKind::Expr { scope, expr } => {
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ impl Direction for Backward {
|
|||
{
|
||||
results.reset_to_block_entry(state, block);
|
||||
|
||||
vis.visit_block_end(results, state, block_data, block);
|
||||
vis.visit_block_end(state);
|
||||
|
||||
// Terminator
|
||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||
|
|
@ -214,7 +214,7 @@ impl Direction for Backward {
|
|||
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
||||
}
|
||||
|
||||
vis.visit_block_start(results, state, block_data, block);
|
||||
vis.visit_block_start(state);
|
||||
}
|
||||
|
||||
fn join_state_into_successors_of<'tcx, A>(
|
||||
|
|
@ -449,7 +449,7 @@ impl Direction for Forward {
|
|||
{
|
||||
results.reset_to_block_entry(state, block);
|
||||
|
||||
vis.visit_block_start(results, state, block_data, block);
|
||||
vis.visit_block_start(state);
|
||||
|
||||
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
|
||||
let loc = Location { block, statement_index };
|
||||
|
|
@ -466,7 +466,7 @@ impl Direction for Forward {
|
|||
results.reconstruct_terminator_effect(state, term, loc);
|
||||
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
||||
|
||||
vis.visit_block_end(results, state, block_data, block);
|
||||
vis.visit_block_end(state);
|
||||
}
|
||||
|
||||
fn join_state_into_successors_of<'tcx, A>(
|
||||
|
|
|
|||
|
|
@ -545,25 +545,13 @@ where
|
|||
{
|
||||
type FlowState = A::Domain;
|
||||
|
||||
fn visit_block_start(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
state: &Self::FlowState,
|
||||
_block_data: &mir::BasicBlockData<'tcx>,
|
||||
_block: BasicBlock,
|
||||
) {
|
||||
fn visit_block_start(&mut self, state: &Self::FlowState) {
|
||||
if A::Direction::IS_FORWARD {
|
||||
self.prev_state.clone_from(state);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_block_end(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
state: &Self::FlowState,
|
||||
_block_data: &mir::BasicBlockData<'tcx>,
|
||||
_block: BasicBlock,
|
||||
) {
|
||||
fn visit_block_end(&mut self, state: &Self::FlowState) {
|
||||
if A::Direction::IS_BACKWARD {
|
||||
self.prev_state.clone_from(state);
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue