Auto merge of #135260 - matthiaskrgr:rollup-8irqs72, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #134228 (Exhaustively handle expressions in patterns) - #135194 (triagebot: mark tidy changes with a more specific `A-tidy` label) - #135222 (Ensure that we don't try to access fields on a non-struct pattern type) - #135250 (A couple simple borrowck cleanups) - #135252 (Fix release notes link) - #135253 (Revert #131365) Failed merges: - #135195 (Make `lit_to_mir_constant` and `lit_to_const` infallible) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e26ff2f908
82 changed files with 759 additions and 506 deletions
|
@ -37,7 +37,7 @@ Libraries
|
||||||
- [Move `<float>::copysign`, `<float>::abs`, `<float>::signum` to `core`](https://github.com/rust-lang/rust/pull/131304)
|
- [Move `<float>::copysign`, `<float>::abs`, `<float>::signum` to `core`](https://github.com/rust-lang/rust/pull/131304)
|
||||||
- [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377)
|
- [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377)
|
||||||
- [Implement `FromStr` for `CString` and `TryFrom<CString>` for `String`](https://github.com/rust-lang/rust/pull/130608)
|
- [Implement `FromStr` for `CString` and `TryFrom<CString>` for `String`](https://github.com/rust-lang/rust/pull/130608)
|
||||||
- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/130635)
|
- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/123723)
|
||||||
|
|
||||||
<a id="1.84.0-Stabilized-APIs"></a>
|
<a id="1.84.0-Stabilized-APIs"></a>
|
||||||
|
|
||||||
|
|
|
@ -623,7 +623,7 @@ impl Pat {
|
||||||
PatKind::Wild
|
PatKind::Wild
|
||||||
| PatKind::Rest
|
| PatKind::Rest
|
||||||
| PatKind::Never
|
| PatKind::Never
|
||||||
| PatKind::Lit(_)
|
| PatKind::Expr(_)
|
||||||
| PatKind::Range(..)
|
| PatKind::Range(..)
|
||||||
| PatKind::Ident(..)
|
| PatKind::Ident(..)
|
||||||
| PatKind::Path(..)
|
| PatKind::Path(..)
|
||||||
|
@ -801,8 +801,8 @@ pub enum PatKind {
|
||||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||||
Ref(P<Pat>, Mutability),
|
Ref(P<Pat>, Mutability),
|
||||||
|
|
||||||
/// A literal.
|
/// A literal, const block or path.
|
||||||
Lit(P<Expr>),
|
Expr(P<Expr>),
|
||||||
|
|
||||||
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
|
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
|
||||||
Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>),
|
Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>),
|
||||||
|
|
|
@ -1512,7 +1512,7 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
|
||||||
vis.visit_ident(ident);
|
vis.visit_ident(ident);
|
||||||
visit_opt(sub, |sub| vis.visit_pat(sub));
|
visit_opt(sub, |sub| vis.visit_pat(sub));
|
||||||
}
|
}
|
||||||
PatKind::Lit(e) => vis.visit_expr(e),
|
PatKind::Expr(e) => vis.visit_expr(e),
|
||||||
PatKind::TupleStruct(qself, path, elems) => {
|
PatKind::TupleStruct(qself, path, elems) => {
|
||||||
vis.visit_qself(qself);
|
vis.visit_qself(qself);
|
||||||
vis.visit_path(path);
|
vis.visit_path(path);
|
||||||
|
|
|
@ -680,7 +680,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
||||||
try_visit!(visitor.visit_ident(ident));
|
try_visit!(visitor.visit_ident(ident));
|
||||||
visit_opt!(visitor, visit_pat, optional_subpattern);
|
visit_opt!(visitor, visit_pat, optional_subpattern);
|
||||||
}
|
}
|
||||||
PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)),
|
PatKind::Expr(expression) => try_visit!(visitor.visit_expr(expression)),
|
||||||
PatKind::Range(lower_bound, upper_bound, _end) => {
|
PatKind::Range(lower_bound, upper_bound, _end) => {
|
||||||
visit_opt!(visitor, visit_expr, lower_bound);
|
visit_opt!(visitor, visit_expr, lower_bound);
|
||||||
visit_opt!(visitor, visit_expr, upper_bound);
|
visit_opt!(visitor, visit_expr, upper_bound);
|
||||||
|
|
|
@ -102,17 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
let kind = match &e.kind {
|
let kind = match &e.kind {
|
||||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||||
ExprKind::ConstBlock(c) => {
|
ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),
|
||||||
let c = self.with_new_scopes(c.value.span, |this| {
|
|
||||||
let def_id = this.local_def_id(c.id);
|
|
||||||
hir::ConstBlock {
|
|
||||||
def_id,
|
|
||||||
hir_id: this.lower_node_id(c.id),
|
|
||||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
hir::ExprKind::ConstBlock(c)
|
|
||||||
}
|
|
||||||
ExprKind::Repeat(expr, count) => {
|
ExprKind::Repeat(expr, count) => {
|
||||||
let expr = self.lower_expr(expr);
|
let expr = self.lower_expr(expr);
|
||||||
let count = self.lower_array_length_to_const_arg(count);
|
let count = self.lower_array_length_to_const_arg(count);
|
||||||
|
@ -153,18 +143,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let ohs = self.lower_expr(ohs);
|
let ohs = self.lower_expr(ohs);
|
||||||
hir::ExprKind::Unary(op, ohs)
|
hir::ExprKind::Unary(op, ohs)
|
||||||
}
|
}
|
||||||
ExprKind::Lit(token_lit) => {
|
ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),
|
||||||
let lit_kind = match LitKind::from_token_lit(*token_lit) {
|
|
||||||
Ok(lit_kind) => lit_kind,
|
|
||||||
Err(err) => {
|
|
||||||
let guar =
|
|
||||||
report_lit_error(&self.tcx.sess.psess, err, *token_lit, e.span);
|
|
||||||
LitKind::Err(guar)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind));
|
|
||||||
hir::ExprKind::Lit(lit)
|
|
||||||
}
|
|
||||||
ExprKind::IncludedBytes(bytes) => {
|
ExprKind::IncludedBytes(bytes) => {
|
||||||
let lit = self.arena.alloc(respan(
|
let lit = self.arena.alloc(respan(
|
||||||
self.lower_span(e.span),
|
self.lower_span(e.span),
|
||||||
|
@ -403,6 +382,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
|
||||||
|
self.with_new_scopes(c.value.span, |this| {
|
||||||
|
let def_id = this.local_def_id(c.id);
|
||||||
|
hir::ConstBlock {
|
||||||
|
def_id,
|
||||||
|
hir_id: this.lower_node_id(c.id),
|
||||||
|
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lower_lit(
|
||||||
|
&mut self,
|
||||||
|
token_lit: &token::Lit,
|
||||||
|
span: Span,
|
||||||
|
) -> &'hir Spanned<LitKind> {
|
||||||
|
let lit_kind = match LitKind::from_token_lit(*token_lit) {
|
||||||
|
Ok(lit_kind) => lit_kind,
|
||||||
|
Err(err) => {
|
||||||
|
let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);
|
||||||
|
LitKind::Err(guar)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.arena.alloc(respan(self.lower_span(span), lit_kind))
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
|
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
|
||||||
match u {
|
match u {
|
||||||
UnOp::Deref => hir::UnOp::Deref,
|
UnOp::Deref => hir::UnOp::Deref,
|
||||||
|
|
|
@ -209,6 +209,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_pat_expr(&mut self, expr: &'hir PatExpr<'hir>) {
|
||||||
|
self.insert(expr.span, expr.hir_id, Node::PatExpr(expr));
|
||||||
|
|
||||||
|
self.with_parent(expr.hir_id, |this| {
|
||||||
|
intravisit::walk_pat_expr(this, expr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) {
|
fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) {
|
||||||
self.insert(field.span, field.hir_id, Node::PatField(field));
|
self.insert(field.span, field.hir_id, Node::PatField(field));
|
||||||
self.with_parent(field.hir_id, |this| {
|
self.with_parent(field.hir_id, |this| {
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#![doc(rust_logo)]
|
#![doc(rust_logo)]
|
||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(if_let_guard)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(rustdoc_internals)]
|
#![feature(rustdoc_internals)]
|
||||||
#![warn(unreachable_pub)]
|
#![warn(unreachable_pub)]
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_middle::span_bug;
|
||||||
|
use rustc_span::source_map::{Spanned, respan};
|
||||||
use rustc_span::{Ident, Span};
|
use rustc_span::{Ident, Span};
|
||||||
|
|
||||||
use super::errors::{
|
use super::errors::{
|
||||||
|
@ -35,8 +38,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
lower_sub,
|
lower_sub,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
PatKind::Lit(e) => {
|
PatKind::Expr(e) => {
|
||||||
break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
|
break hir::PatKind::Expr(self.lower_expr_within_pat(e, false));
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(qself, path, pats) => {
|
PatKind::TupleStruct(qself, path, pats) => {
|
||||||
let qpath = self.lower_qpath(
|
let qpath = self.lower_qpath(
|
||||||
|
@ -367,24 +370,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// }
|
// }
|
||||||
// m!(S);
|
// m!(S);
|
||||||
// ```
|
// ```
|
||||||
fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
|
fn lower_expr_within_pat(
|
||||||
match &expr.kind {
|
&mut self,
|
||||||
ExprKind::Lit(..)
|
expr: &Expr,
|
||||||
| ExprKind::ConstBlock(..)
|
allow_paths: bool,
|
||||||
| ExprKind::IncludedBytes(..)
|
) -> &'hir hir::PatExpr<'hir> {
|
||||||
| ExprKind::Err(_)
|
let err = |guar| hir::PatExprKind::Lit {
|
||||||
| ExprKind::Dummy => {}
|
lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))),
|
||||||
ExprKind::Path(..) if allow_paths => {}
|
negated: false,
|
||||||
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
|
};
|
||||||
|
let kind = match &expr.kind {
|
||||||
|
ExprKind::Lit(lit) => {
|
||||||
|
hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false }
|
||||||
|
}
|
||||||
|
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
|
||||||
|
ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit {
|
||||||
|
lit: self.arena.alloc(respan(
|
||||||
|
self.lower_span(expr.span),
|
||||||
|
LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked),
|
||||||
|
)),
|
||||||
|
negated: false,
|
||||||
|
},
|
||||||
|
ExprKind::Err(guar) => err(*guar),
|
||||||
|
ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"),
|
||||||
|
ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath(
|
||||||
|
expr.id,
|
||||||
|
qself,
|
||||||
|
path,
|
||||||
|
ParamMode::Optional,
|
||||||
|
AllowReturnTypeNotation::No,
|
||||||
|
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||||
|
None,
|
||||||
|
)),
|
||||||
|
ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => {
|
||||||
|
hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true }
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let pattern_from_macro = expr.is_approximately_pattern();
|
let pattern_from_macro = expr.is_approximately_pattern();
|
||||||
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
|
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
pattern_from_macro_note: pattern_from_macro,
|
pattern_from_macro_note: pattern_from_macro,
|
||||||
});
|
});
|
||||||
return self.arena.alloc(self.expr_err(expr.span, guar));
|
err(guar)
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
self.lower_expr(expr)
|
self.arena.alloc(hir::PatExpr {
|
||||||
|
hir_id: self.lower_node_id(expr.id),
|
||||||
|
span: expr.span,
|
||||||
|
kind,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1701,7 +1701,7 @@ impl<'a> State<'a> {
|
||||||
self.print_pat(inner);
|
self.print_pat(inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Lit(e) => self.print_expr(e, FixupContext::default()),
|
PatKind::Expr(e) => self.print_expr(e, FixupContext::default()),
|
||||||
PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
|
PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
|
||||||
if let Some(e) = begin {
|
if let Some(e) = begin {
|
||||||
self.print_expr(e, FixupContext::default());
|
self.print_expr(e, FixupContext::default());
|
||||||
|
|
|
@ -11,8 +11,8 @@ pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_a
|
||||||
pub use super::place_ext::PlaceExt;
|
pub use super::place_ext::PlaceExt;
|
||||||
pub use super::places_conflict::{PlaceConflictBias, places_conflict};
|
pub use super::places_conflict::{PlaceConflictBias, places_conflict};
|
||||||
pub use super::polonius::legacy::{
|
pub use super::polonius::legacy::{
|
||||||
AllFacts as PoloniusInput, LocationTable, PoloniusOutput, PoloniusRegionVid, RichLocation,
|
PoloniusFacts as PoloniusInput, PoloniusLocationTable, PoloniusOutput, PoloniusRegionVid,
|
||||||
RustcFacts,
|
RichLocation, RustcFacts,
|
||||||
};
|
};
|
||||||
pub use super::region_infer::RegionInferenceContext;
|
pub use super::region_infer::RegionInferenceContext;
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ pub enum ConsumerOptions {
|
||||||
/// without significant slowdowns.
|
/// without significant slowdowns.
|
||||||
///
|
///
|
||||||
/// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext),
|
/// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext),
|
||||||
/// and additionally retrieve the [`LocationTable`] and [`PoloniusInput`] that
|
/// and additionally retrieve the [`PoloniusLocationTable`] and [`PoloniusInput`] that
|
||||||
/// would be given to Polonius. Critically, this does not run Polonius, which
|
/// would be given to Polonius. Critically, this does not run Polonius, which
|
||||||
/// one may want to avoid due to performance issues on large bodies.
|
/// one may want to avoid due to performance issues on large bodies.
|
||||||
PoloniusInputFacts,
|
PoloniusInputFacts,
|
||||||
|
@ -71,7 +71,7 @@ pub struct BodyWithBorrowckFacts<'tcx> {
|
||||||
/// The table that maps Polonius points to locations in the table.
|
/// The table that maps Polonius points to locations in the table.
|
||||||
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
||||||
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
||||||
pub location_table: Option<LocationTable>,
|
pub location_table: Option<PoloniusLocationTable>,
|
||||||
/// Polonius input facts.
|
/// Polonius input facts.
|
||||||
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
||||||
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
||||||
|
|
|
@ -60,7 +60,7 @@ use crate::diagnostics::{
|
||||||
use crate::path_utils::*;
|
use crate::path_utils::*;
|
||||||
use crate::place_ext::PlaceExt;
|
use crate::place_ext::PlaceExt;
|
||||||
use crate::places_conflict::{PlaceConflictBias, places_conflict};
|
use crate::places_conflict::{PlaceConflictBias, places_conflict};
|
||||||
use crate::polonius::legacy::{LocationTable, PoloniusOutput};
|
use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
|
||||||
use crate::prefixes::PrefixSet;
|
use crate::prefixes::PrefixSet;
|
||||||
use crate::region_infer::RegionInferenceContext;
|
use crate::region_infer::RegionInferenceContext;
|
||||||
use crate::renumber::RegionCtxt;
|
use crate::renumber::RegionCtxt;
|
||||||
|
@ -179,7 +179,7 @@ fn do_mir_borrowck<'tcx>(
|
||||||
infcx.register_predefined_opaques_for_next_solver(def);
|
infcx.register_predefined_opaques_for_next_solver(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
let location_table = LocationTable::new(body);
|
let location_table = PoloniusLocationTable::new(body);
|
||||||
|
|
||||||
let move_data = MoveData::gather_moves(body, tcx, |_| true);
|
let move_data = MoveData::gather_moves(body, tcx, |_| true);
|
||||||
let promoted_move_data = promoted
|
let promoted_move_data = promoted
|
||||||
|
@ -250,7 +250,8 @@ fn do_mir_borrowck<'tcx>(
|
||||||
infcx: &infcx,
|
infcx: &infcx,
|
||||||
body: promoted_body,
|
body: promoted_body,
|
||||||
move_data: &move_data,
|
move_data: &move_data,
|
||||||
location_table: &location_table, // no need to create a real one for the promoted, it is not used
|
// no need to create a real location table for the promoted, it is not used
|
||||||
|
location_table: &location_table,
|
||||||
movable_coroutine,
|
movable_coroutine,
|
||||||
fn_self_span_reported: Default::default(),
|
fn_self_span_reported: Default::default(),
|
||||||
locals_are_invalidated_at_exit,
|
locals_are_invalidated_at_exit,
|
||||||
|
@ -516,7 +517,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
||||||
|
|
||||||
/// Map from MIR `Location` to `LocationIndex`; created
|
/// Map from MIR `Location` to `LocationIndex`; created
|
||||||
/// when MIR borrowck begins.
|
/// when MIR borrowck begins.
|
||||||
location_table: &'a LocationTable,
|
location_table: &'a PoloniusLocationTable,
|
||||||
|
|
||||||
movable_coroutine: bool,
|
movable_coroutine: bool,
|
||||||
/// This keeps track of whether local variables are free-ed when the function
|
/// This keeps track of whether local variables are free-ed when the function
|
||||||
|
|
|
@ -28,7 +28,9 @@ use crate::borrow_set::BorrowSet;
|
||||||
use crate::consumers::ConsumerOptions;
|
use crate::consumers::ConsumerOptions;
|
||||||
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
|
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
|
||||||
use crate::polonius::LocalizedOutlivesConstraintSet;
|
use crate::polonius::LocalizedOutlivesConstraintSet;
|
||||||
use crate::polonius::legacy::{AllFacts, AllFactsExt, LocationTable, PoloniusOutput};
|
use crate::polonius::legacy::{
|
||||||
|
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||||
|
};
|
||||||
use crate::region_infer::RegionInferenceContext;
|
use crate::region_infer::RegionInferenceContext;
|
||||||
use crate::type_check::{self, MirTypeckResults};
|
use crate::type_check::{self, MirTypeckResults};
|
||||||
use crate::universal_regions::UniversalRegions;
|
use crate::universal_regions::UniversalRegions;
|
||||||
|
@ -39,7 +41,7 @@ use crate::{BorrowckInferCtxt, polonius, renumber};
|
||||||
pub(crate) struct NllOutput<'tcx> {
|
pub(crate) struct NllOutput<'tcx> {
|
||||||
pub regioncx: RegionInferenceContext<'tcx>,
|
pub regioncx: RegionInferenceContext<'tcx>,
|
||||||
pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||||
pub polonius_input: Option<Box<AllFacts>>,
|
pub polonius_input: Option<Box<PoloniusFacts>>,
|
||||||
pub polonius_output: Option<Box<PoloniusOutput>>,
|
pub polonius_output: Option<Box<PoloniusOutput>>,
|
||||||
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
|
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
|
||||||
pub nll_errors: RegionErrors<'tcx>,
|
pub nll_errors: RegionErrors<'tcx>,
|
||||||
|
@ -80,7 +82,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
universal_regions: UniversalRegions<'tcx>,
|
universal_regions: UniversalRegions<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
|
@ -91,10 +93,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
|| is_polonius_legacy_enabled;
|
|| is_polonius_legacy_enabled;
|
||||||
let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
|
let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
|
||||||
|| is_polonius_legacy_enabled;
|
|| is_polonius_legacy_enabled;
|
||||||
let mut all_facts =
|
let mut polonius_facts =
|
||||||
(polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
|
(polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
|
||||||
|
|
||||||
let elements = Rc::new(DenseLocationMap::new(body));
|
let location_map = Rc::new(DenseLocationMap::new(body));
|
||||||
|
|
||||||
// Run the MIR type-checker.
|
// Run the MIR type-checker.
|
||||||
let MirTypeckResults {
|
let MirTypeckResults {
|
||||||
|
@ -109,10 +111,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
universal_regions,
|
universal_regions,
|
||||||
location_table,
|
location_table,
|
||||||
borrow_set,
|
borrow_set,
|
||||||
&mut all_facts,
|
&mut polonius_facts,
|
||||||
flow_inits,
|
flow_inits,
|
||||||
move_data,
|
move_data,
|
||||||
Rc::clone(&elements),
|
Rc::clone(&location_map),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the region inference context, taking ownership of the
|
// Create the region inference context, taking ownership of the
|
||||||
|
@ -122,7 +124,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
|
|
||||||
// If requested, emit legacy polonius facts.
|
// If requested, emit legacy polonius facts.
|
||||||
polonius::legacy::emit_facts(
|
polonius::legacy::emit_facts(
|
||||||
&mut all_facts,
|
&mut polonius_facts,
|
||||||
infcx.tcx,
|
infcx.tcx,
|
||||||
location_table,
|
location_table,
|
||||||
body,
|
body,
|
||||||
|
@ -137,7 +139,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
var_infos,
|
var_infos,
|
||||||
constraints,
|
constraints,
|
||||||
universal_region_relations,
|
universal_region_relations,
|
||||||
elements,
|
location_map,
|
||||||
);
|
);
|
||||||
|
|
||||||
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives
|
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives
|
||||||
|
@ -147,13 +149,13 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
});
|
});
|
||||||
|
|
||||||
// If requested: dump NLL facts, and run legacy polonius analysis.
|
// If requested: dump NLL facts, and run legacy polonius analysis.
|
||||||
let polonius_output = all_facts.as_ref().and_then(|all_facts| {
|
let polonius_output = polonius_facts.as_ref().and_then(|polonius_facts| {
|
||||||
if infcx.tcx.sess.opts.unstable_opts.nll_facts {
|
if infcx.tcx.sess.opts.unstable_opts.nll_facts {
|
||||||
let def_id = body.source.def_id();
|
let def_id = body.source.def_id();
|
||||||
let def_path = infcx.tcx.def_path(def_id);
|
let def_path = infcx.tcx.def_path(def_id);
|
||||||
let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir)
|
let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir)
|
||||||
.join(def_path.to_filename_friendly_no_crate());
|
.join(def_path.to_filename_friendly_no_crate());
|
||||||
all_facts.write_to_dir(dir_path, location_table).unwrap();
|
polonius_facts.write_to_dir(dir_path, location_table).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if polonius_output {
|
if polonius_output {
|
||||||
|
@ -162,7 +164,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
let algorithm = Algorithm::from_str(&algorithm).unwrap();
|
let algorithm = Algorithm::from_str(&algorithm).unwrap();
|
||||||
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
|
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
|
||||||
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis");
|
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis");
|
||||||
Some(Box::new(Output::compute(all_facts, algorithm, false)))
|
Some(Box::new(Output::compute(polonius_facts, algorithm, false)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -182,7 +184,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||||
NllOutput {
|
NllOutput {
|
||||||
regioncx,
|
regioncx,
|
||||||
opaque_type_values: remapped_opaque_tys,
|
opaque_type_values: remapped_opaque_tys,
|
||||||
polonius_input: all_facts.map(Box::new),
|
polonius_input: polonius_facts.map(Box::new),
|
||||||
polonius_output,
|
polonius_output,
|
||||||
opt_closure_req: closure_region_requirements,
|
opt_closure_req: closure_region_requirements,
|
||||||
nll_errors,
|
nll_errors,
|
||||||
|
|
|
@ -4,16 +4,16 @@ use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_mir_dataflow::move_paths::{LookupResult, MoveData};
|
use rustc_mir_dataflow::move_paths::{LookupResult, MoveData};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use super::{AllFacts, LocationIndex, LocationTable};
|
use super::{LocationIndex, PoloniusFacts, PoloniusLocationTable};
|
||||||
use crate::def_use::{self, DefUse};
|
use crate::def_use::{self, DefUse};
|
||||||
use crate::universal_regions::UniversalRegions;
|
use crate::universal_regions::UniversalRegions;
|
||||||
|
|
||||||
/// Emit polonius facts for variable defs, uses, drops, and path accesses.
|
/// Emit polonius facts for variable defs, uses, drops, and path accesses.
|
||||||
pub(crate) fn emit_access_facts<'tcx>(
|
pub(crate) fn emit_access_facts<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
facts: &mut AllFacts,
|
facts: &mut PoloniusFacts,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
universal_regions: &UniversalRegions<'tcx>,
|
universal_regions: &UniversalRegions<'tcx>,
|
||||||
) {
|
) {
|
||||||
|
@ -31,9 +31,9 @@ pub(crate) fn emit_access_facts<'tcx>(
|
||||||
|
|
||||||
/// MIR visitor extracting point-wise facts about accesses.
|
/// MIR visitor extracting point-wise facts about accesses.
|
||||||
struct AccessFactsExtractor<'a, 'tcx> {
|
struct AccessFactsExtractor<'a, 'tcx> {
|
||||||
facts: &'a mut AllFacts,
|
facts: &'a mut PoloniusFacts,
|
||||||
move_data: &'a MoveData<'tcx>,
|
move_data: &'a MoveData<'tcx>,
|
||||||
location_table: &'a LocationTable,
|
location_table: &'a PoloniusLocationTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> AccessFactsExtractor<'_, 'tcx> {
|
impl<'tcx> AccessFactsExtractor<'_, 'tcx> {
|
||||||
|
|
|
@ -4,13 +4,13 @@ use std::fs::{self, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use polonius_engine::{AllFacts as PoloniusFacts, Atom, Output};
|
use polonius_engine::{AllFacts, Atom, Output};
|
||||||
use rustc_macros::extension;
|
use rustc_macros::extension;
|
||||||
use rustc_middle::mir::Local;
|
use rustc_middle::mir::Local;
|
||||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||||
use rustc_mir_dataflow::move_paths::MovePathIndex;
|
use rustc_mir_dataflow::move_paths::MovePathIndex;
|
||||||
|
|
||||||
use super::{LocationIndex, LocationTable};
|
use super::{LocationIndex, PoloniusLocationTable};
|
||||||
use crate::BorrowIndex;
|
use crate::BorrowIndex;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -49,11 +49,11 @@ impl polonius_engine::FactTypes for RustcFacts {
|
||||||
type Path = MovePathIndex;
|
type Path = MovePathIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type AllFacts = PoloniusFacts<RustcFacts>;
|
pub type PoloniusFacts = AllFacts<RustcFacts>;
|
||||||
|
|
||||||
#[extension(pub(crate) trait AllFactsExt)]
|
#[extension(pub(crate) trait PoloniusFactsExt)]
|
||||||
impl AllFacts {
|
impl PoloniusFacts {
|
||||||
/// Returns `true` if there is a need to gather `AllFacts` given the
|
/// Returns `true` if there is a need to gather `PoloniusFacts` given the
|
||||||
/// current `-Z` flags.
|
/// current `-Z` flags.
|
||||||
fn enabled(tcx: TyCtxt<'_>) -> bool {
|
fn enabled(tcx: TyCtxt<'_>) -> bool {
|
||||||
tcx.sess.opts.unstable_opts.nll_facts
|
tcx.sess.opts.unstable_opts.nll_facts
|
||||||
|
@ -63,7 +63,7 @@ impl AllFacts {
|
||||||
fn write_to_dir(
|
fn write_to_dir(
|
||||||
&self,
|
&self,
|
||||||
dir: impl AsRef<Path>,
|
dir: impl AsRef<Path>,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
let dir: &Path = dir.as_ref();
|
let dir: &Path = dir.as_ref();
|
||||||
fs::create_dir_all(dir)?;
|
fs::create_dir_all(dir)?;
|
||||||
|
@ -119,7 +119,7 @@ impl Atom for LocationIndex {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FactWriter<'w> {
|
struct FactWriter<'w> {
|
||||||
location_table: &'w LocationTable,
|
location_table: &'w PoloniusLocationTable,
|
||||||
dir: &'w Path,
|
dir: &'w Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ trait FactRow {
|
||||||
fn write(
|
fn write(
|
||||||
&self,
|
&self,
|
||||||
out: &mut dyn Write,
|
out: &mut dyn Write,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
) -> Result<(), Box<dyn Error>>;
|
) -> Result<(), Box<dyn Error>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ impl FactRow for PoloniusRegionVid {
|
||||||
fn write(
|
fn write(
|
||||||
&self,
|
&self,
|
||||||
out: &mut dyn Write,
|
out: &mut dyn Write,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
write_row(out, location_table, &[self])
|
write_row(out, location_table, &[self])
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ where
|
||||||
fn write(
|
fn write(
|
||||||
&self,
|
&self,
|
||||||
out: &mut dyn Write,
|
out: &mut dyn Write,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
write_row(out, location_table, &[&self.0, &self.1])
|
write_row(out, location_table, &[&self.0, &self.1])
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ where
|
||||||
fn write(
|
fn write(
|
||||||
&self,
|
&self,
|
||||||
out: &mut dyn Write,
|
out: &mut dyn Write,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
write_row(out, location_table, &[&self.0, &self.1, &self.2])
|
write_row(out, location_table, &[&self.0, &self.1, &self.2])
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ where
|
||||||
fn write(
|
fn write(
|
||||||
&self,
|
&self,
|
||||||
out: &mut dyn Write,
|
out: &mut dyn Write,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
|
write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ where
|
||||||
|
|
||||||
fn write_row(
|
fn write_row(
|
||||||
out: &mut dyn Write,
|
out: &mut dyn Write,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
columns: &[&dyn FactCell],
|
columns: &[&dyn FactCell],
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
for (index, c) in columns.iter().enumerate() {
|
for (index, c) in columns.iter().enumerate() {
|
||||||
|
@ -213,41 +213,41 @@ fn write_row(
|
||||||
}
|
}
|
||||||
|
|
||||||
trait FactCell {
|
trait FactCell {
|
||||||
fn to_string(&self, location_table: &LocationTable) -> String;
|
fn to_string(&self, location_table: &PoloniusLocationTable) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FactCell for BorrowIndex {
|
impl FactCell for BorrowIndex {
|
||||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||||
format!("{self:?}")
|
format!("{self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FactCell for Local {
|
impl FactCell for Local {
|
||||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||||
format!("{self:?}")
|
format!("{self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FactCell for MovePathIndex {
|
impl FactCell for MovePathIndex {
|
||||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||||
format!("{self:?}")
|
format!("{self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FactCell for PoloniusRegionVid {
|
impl FactCell for PoloniusRegionVid {
|
||||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||||
format!("{self:?}")
|
format!("{self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FactCell for RegionVid {
|
impl FactCell for RegionVid {
|
||||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||||
format!("{self:?}")
|
format!("{self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FactCell for LocationIndex {
|
impl FactCell for LocationIndex {
|
||||||
fn to_string(&self, location_table: &LocationTable) -> String {
|
fn to_string(&self, location_table: &PoloniusLocationTable) -> String {
|
||||||
format!("{:?}", location_table.to_rich_location(*self))
|
format!("{:?}", location_table.to_rich_location(*self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use rustc_middle::mir::{
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use super::{AllFacts, LocationTable};
|
use super::{PoloniusFacts, PoloniusLocationTable};
|
||||||
use crate::borrow_set::BorrowSet;
|
use crate::borrow_set::BorrowSet;
|
||||||
use crate::path_utils::*;
|
use crate::path_utils::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -22,9 +22,9 @@ use crate::{
|
||||||
/// Emit `loan_invalidated_at` facts.
|
/// Emit `loan_invalidated_at` facts.
|
||||||
pub(super) fn emit_loan_invalidations<'tcx>(
|
pub(super) fn emit_loan_invalidations<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
facts: &mut AllFacts,
|
facts: &mut PoloniusFacts,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
) {
|
) {
|
||||||
let dominators = body.basic_blocks.dominators();
|
let dominators = body.basic_blocks.dominators();
|
||||||
|
@ -35,9 +35,9 @@ pub(super) fn emit_loan_invalidations<'tcx>(
|
||||||
|
|
||||||
struct LoanInvalidationsGenerator<'a, 'tcx> {
|
struct LoanInvalidationsGenerator<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
facts: &'a mut AllFacts,
|
facts: &'a mut PoloniusFacts,
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
location_table: &'a LocationTable,
|
location_table: &'a PoloniusLocationTable,
|
||||||
dominators: &'a Dominators<BasicBlock>,
|
dominators: &'a Dominators<BasicBlock>,
|
||||||
borrow_set: &'a BorrowSet<'tcx>,
|
borrow_set: &'a BorrowSet<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,16 @@ use rustc_middle::mir::{
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use super::{AllFacts, LocationTable};
|
use super::{PoloniusFacts, PoloniusLocationTable};
|
||||||
use crate::borrow_set::BorrowSet;
|
use crate::borrow_set::BorrowSet;
|
||||||
use crate::places_conflict;
|
use crate::places_conflict;
|
||||||
|
|
||||||
/// Emit `loan_killed_at` and `cfg_edge` facts at the same time.
|
/// Emit `loan_killed_at` and `cfg_edge` facts at the same time.
|
||||||
pub(super) fn emit_loan_kills<'tcx>(
|
pub(super) fn emit_loan_kills<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
facts: &mut AllFacts,
|
facts: &mut PoloniusFacts,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
) {
|
) {
|
||||||
let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, facts, body };
|
let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, facts, body };
|
||||||
|
@ -26,8 +26,8 @@ pub(super) fn emit_loan_kills<'tcx>(
|
||||||
|
|
||||||
struct LoanKillsGenerator<'a, 'tcx> {
|
struct LoanKillsGenerator<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
facts: &'a mut AllFacts,
|
facts: &'a mut PoloniusFacts,
|
||||||
location_table: &'a LocationTable,
|
location_table: &'a PoloniusLocationTable,
|
||||||
borrow_set: &'a BorrowSet<'tcx>,
|
borrow_set: &'a BorrowSet<'tcx>,
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use tracing::debug;
|
||||||
/// granularity through outlives relations; however, the rich location
|
/// granularity through outlives relations; however, the rich location
|
||||||
/// table serves another purpose: it compresses locations from
|
/// table serves another purpose: it compresses locations from
|
||||||
/// multiple words into a single u32.
|
/// multiple words into a single u32.
|
||||||
pub struct LocationTable {
|
pub struct PoloniusLocationTable {
|
||||||
num_points: usize,
|
num_points: usize,
|
||||||
statements_before_block: IndexVec<BasicBlock, usize>,
|
statements_before_block: IndexVec<BasicBlock, usize>,
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ pub enum RichLocation {
|
||||||
Mid(Location),
|
Mid(Location),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocationTable {
|
impl PoloniusLocationTable {
|
||||||
pub(crate) fn new(body: &Body<'_>) -> Self {
|
pub(crate) fn new(body: &Body<'_>) -> Self {
|
||||||
let mut num_points = 0;
|
let mut num_points = 0;
|
||||||
let statements_before_block = body
|
let statements_before_block = body
|
||||||
|
@ -43,8 +43,8 @@ impl LocationTable {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
debug!("LocationTable(statements_before_block={:#?})", statements_before_block);
|
debug!("PoloniusLocationTable(statements_before_block={:#?})", statements_before_block);
|
||||||
debug!("LocationTable: num_points={:#?}", num_points);
|
debug!("PoloniusLocationTable: num_points={:#?}", num_points);
|
||||||
|
|
||||||
Self { num_points, statements_before_block }
|
Self { num_points, statements_before_block }
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,16 +36,16 @@ pub use self::facts::*;
|
||||||
///
|
///
|
||||||
/// The rest of the facts are emitted during typeck and liveness.
|
/// The rest of the facts are emitted during typeck and liveness.
|
||||||
pub(crate) fn emit_facts<'tcx>(
|
pub(crate) fn emit_facts<'tcx>(
|
||||||
all_facts: &mut Option<AllFacts>,
|
facts: &mut Option<PoloniusFacts>,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
universal_region_relations: &UniversalRegionRelations<'tcx>,
|
universal_region_relations: &UniversalRegionRelations<'tcx>,
|
||||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||||
) {
|
) {
|
||||||
let Some(facts) = all_facts else {
|
let Some(facts) = facts else {
|
||||||
// We don't do anything if there are no facts to fill.
|
// We don't do anything if there are no facts to fill.
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -67,9 +67,9 @@ pub(crate) fn emit_facts<'tcx>(
|
||||||
|
|
||||||
/// Emit facts needed for move/init analysis: moves and assignments.
|
/// Emit facts needed for move/init analysis: moves and assignments.
|
||||||
fn emit_move_facts(
|
fn emit_move_facts(
|
||||||
facts: &mut AllFacts,
|
facts: &mut PoloniusFacts,
|
||||||
body: &Body<'_>,
|
body: &Body<'_>,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
move_data: &MoveData<'_>,
|
move_data: &MoveData<'_>,
|
||||||
) {
|
) {
|
||||||
facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
|
facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
|
||||||
|
@ -139,7 +139,7 @@ fn emit_move_facts(
|
||||||
|
|
||||||
/// Emit universal regions facts, and their relations.
|
/// Emit universal regions facts, and their relations.
|
||||||
fn emit_universal_region_facts(
|
fn emit_universal_region_facts(
|
||||||
facts: &mut AllFacts,
|
facts: &mut PoloniusFacts,
|
||||||
borrow_set: &BorrowSet<'_>,
|
borrow_set: &BorrowSet<'_>,
|
||||||
universal_region_relations: &UniversalRegionRelations<'_>,
|
universal_region_relations: &UniversalRegionRelations<'_>,
|
||||||
) {
|
) {
|
||||||
|
@ -187,10 +187,10 @@ pub(crate) fn emit_drop_facts<'tcx>(
|
||||||
local: Local,
|
local: Local,
|
||||||
kind: &GenericArg<'tcx>,
|
kind: &GenericArg<'tcx>,
|
||||||
universal_regions: &UniversalRegions<'tcx>,
|
universal_regions: &UniversalRegions<'tcx>,
|
||||||
all_facts: &mut Option<AllFacts>,
|
facts: &mut Option<PoloniusFacts>,
|
||||||
) {
|
) {
|
||||||
debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind);
|
debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind);
|
||||||
let Some(facts) = all_facts.as_mut() else { return };
|
let Some(facts) = facts.as_mut() else { return };
|
||||||
let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
|
let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
|
||||||
tcx.for_each_free_region(kind, |drop_live_region| {
|
tcx.for_each_free_region(kind, |drop_live_region| {
|
||||||
let region_vid = universal_regions.to_region_vid(drop_live_region);
|
let region_vid = universal_regions.to_region_vid(drop_live_region);
|
||||||
|
@ -201,8 +201,8 @@ pub(crate) fn emit_drop_facts<'tcx>(
|
||||||
/// Emit facts about the outlives constraints: the `subset` base relation, i.e. not a transitive
|
/// Emit facts about the outlives constraints: the `subset` base relation, i.e. not a transitive
|
||||||
/// closure.
|
/// closure.
|
||||||
fn emit_outlives_facts<'tcx>(
|
fn emit_outlives_facts<'tcx>(
|
||||||
facts: &mut AllFacts,
|
facts: &mut PoloniusFacts,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||||
) {
|
) {
|
||||||
facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map(
|
facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map(
|
||||||
|
|
|
@ -392,7 +392,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
var_infos: VarInfos,
|
var_infos: VarInfos,
|
||||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||||
elements: Rc<DenseLocationMap>,
|
location_map: Rc<DenseLocationMap>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let universal_regions = &universal_region_relations.universal_regions;
|
let universal_regions = &universal_region_relations.universal_regions;
|
||||||
let MirTypeckRegionConstraints {
|
let MirTypeckRegionConstraints {
|
||||||
|
@ -436,7 +436,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut scc_values =
|
let mut scc_values =
|
||||||
RegionValues::new(elements, universal_regions.len(), placeholder_indices);
|
RegionValues::new(location_map, universal_regions.len(), placeholder_indices);
|
||||||
|
|
||||||
for region in liveness_constraints.regions() {
|
for region in liveness_constraints.regions() {
|
||||||
let scc = constraint_sccs.scc(region);
|
let scc = constraint_sccs.scc(region);
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub(crate) enum RegionElement {
|
||||||
/// an interval matrix storing liveness ranges for each region-vid.
|
/// an interval matrix storing liveness ranges for each region-vid.
|
||||||
pub(crate) struct LivenessValues {
|
pub(crate) struct LivenessValues {
|
||||||
/// The map from locations to points.
|
/// The map from locations to points.
|
||||||
elements: Rc<DenseLocationMap>,
|
location_map: Rc<DenseLocationMap>,
|
||||||
|
|
||||||
/// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and
|
/// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and
|
||||||
/// currently only used for validating promoteds (which don't care about more precise tracking).
|
/// currently only used for validating promoteds (which don't care about more precise tracking).
|
||||||
|
@ -77,11 +77,11 @@ impl LiveLoans {
|
||||||
|
|
||||||
impl LivenessValues {
|
impl LivenessValues {
|
||||||
/// Create an empty map of regions to locations where they're live.
|
/// Create an empty map of regions to locations where they're live.
|
||||||
pub(crate) fn with_specific_points(elements: Rc<DenseLocationMap>) -> Self {
|
pub(crate) fn with_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
|
||||||
LivenessValues {
|
LivenessValues {
|
||||||
live_regions: None,
|
live_regions: None,
|
||||||
points: Some(SparseIntervalMatrix::new(elements.num_points())),
|
points: Some(SparseIntervalMatrix::new(location_map.num_points())),
|
||||||
elements,
|
location_map,
|
||||||
loans: None,
|
loans: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,11 +90,11 @@ impl LivenessValues {
|
||||||
///
|
///
|
||||||
/// Unlike `with_specific_points`, does not track exact locations where something is live, only
|
/// Unlike `with_specific_points`, does not track exact locations where something is live, only
|
||||||
/// which regions are live.
|
/// which regions are live.
|
||||||
pub(crate) fn without_specific_points(elements: Rc<DenseLocationMap>) -> Self {
|
pub(crate) fn without_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
|
||||||
LivenessValues {
|
LivenessValues {
|
||||||
live_regions: Some(Default::default()),
|
live_regions: Some(Default::default()),
|
||||||
points: None,
|
points: None,
|
||||||
elements,
|
location_map,
|
||||||
loans: None,
|
loans: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,11 +122,11 @@ impl LivenessValues {
|
||||||
|
|
||||||
/// Records `region` as being live at the given `location`.
|
/// Records `region` as being live at the given `location`.
|
||||||
pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
|
pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
|
||||||
let point = self.elements.point_from_location(location);
|
let point = self.location_map.point_from_location(location);
|
||||||
debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
|
debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
|
||||||
if let Some(points) = &mut self.points {
|
if let Some(points) = &mut self.points {
|
||||||
points.insert(region, point);
|
points.insert(region, point);
|
||||||
} else if self.elements.point_in_range(point) {
|
} else if self.location_map.point_in_range(point) {
|
||||||
self.live_regions.as_mut().unwrap().insert(region);
|
self.live_regions.as_mut().unwrap().insert(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ impl LivenessValues {
|
||||||
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
|
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
|
||||||
if let Some(this) = &mut self.points {
|
if let Some(this) = &mut self.points {
|
||||||
this.union_row(region, points);
|
this.union_row(region, points);
|
||||||
} else if points.iter().any(|point| self.elements.point_in_range(point)) {
|
} else if points.iter().any(|point| self.location_map.point_in_range(point)) {
|
||||||
self.live_regions.as_mut().unwrap().insert(region);
|
self.live_regions.as_mut().unwrap().insert(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ impl LivenessValues {
|
||||||
|
|
||||||
/// Returns whether `region` is marked live at the given `location`.
|
/// Returns whether `region` is marked live at the given `location`.
|
||||||
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
|
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
|
||||||
let point = self.elements.point_from_location(location);
|
let point = self.location_map.point_from_location(location);
|
||||||
if let Some(points) = &self.points {
|
if let Some(points) = &self.points {
|
||||||
points.row(region).is_some_and(|r| r.contains(point))
|
points.row(region).is_some_and(|r| r.contains(point))
|
||||||
} else {
|
} else {
|
||||||
|
@ -191,25 +191,26 @@ impl LivenessValues {
|
||||||
.row(region)
|
.row(region)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|set| set.iter())
|
.flat_map(|set| set.iter())
|
||||||
.take_while(|&p| self.elements.point_in_range(p))
|
.take_while(|&p| self.location_map.point_in_range(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For debugging purposes, returns a pretty-printed string of the points where the `region` is
|
/// For debugging purposes, returns a pretty-printed string of the points where the `region` is
|
||||||
/// live.
|
/// live.
|
||||||
pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
|
pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
|
||||||
pretty_print_region_elements(
|
pretty_print_region_elements(
|
||||||
self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))),
|
self.live_points(region)
|
||||||
|
.map(|p| RegionElement::Location(self.location_map.to_location(p))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
|
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
|
||||||
self.elements.point_from_location(location)
|
self.location_map.point_from_location(location)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn location_from_point(&self, point: PointIndex) -> Location {
|
pub(crate) fn location_from_point(&self, point: PointIndex) -> Location {
|
||||||
self.elements.to_location(point)
|
self.location_map.to_location(point)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
|
/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
|
||||||
|
@ -272,7 +273,7 @@ impl PlaceholderIndices {
|
||||||
/// because (since it is returned) it must live for at least `'a`. But
|
/// because (since it is returned) it must live for at least `'a`. But
|
||||||
/// it would also contain various points from within the function.
|
/// it would also contain various points from within the function.
|
||||||
pub(crate) struct RegionValues<N: Idx> {
|
pub(crate) struct RegionValues<N: Idx> {
|
||||||
elements: Rc<DenseLocationMap>,
|
location_map: Rc<DenseLocationMap>,
|
||||||
placeholder_indices: PlaceholderIndices,
|
placeholder_indices: PlaceholderIndices,
|
||||||
points: SparseIntervalMatrix<N, PointIndex>,
|
points: SparseIntervalMatrix<N, PointIndex>,
|
||||||
free_regions: SparseBitMatrix<N, RegionVid>,
|
free_regions: SparseBitMatrix<N, RegionVid>,
|
||||||
|
@ -287,14 +288,14 @@ impl<N: Idx> RegionValues<N> {
|
||||||
/// Each of the regions in num_region_variables will be initialized with an
|
/// Each of the regions in num_region_variables will be initialized with an
|
||||||
/// empty set of points and no causal information.
|
/// empty set of points and no causal information.
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
elements: Rc<DenseLocationMap>,
|
location_map: Rc<DenseLocationMap>,
|
||||||
num_universal_regions: usize,
|
num_universal_regions: usize,
|
||||||
placeholder_indices: PlaceholderIndices,
|
placeholder_indices: PlaceholderIndices,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let num_points = elements.num_points();
|
let num_points = location_map.num_points();
|
||||||
let num_placeholders = placeholder_indices.len();
|
let num_placeholders = placeholder_indices.len();
|
||||||
Self {
|
Self {
|
||||||
elements,
|
location_map,
|
||||||
points: SparseIntervalMatrix::new(num_points),
|
points: SparseIntervalMatrix::new(num_points),
|
||||||
placeholder_indices,
|
placeholder_indices,
|
||||||
free_regions: SparseBitMatrix::new(num_universal_regions),
|
free_regions: SparseBitMatrix::new(num_universal_regions),
|
||||||
|
@ -336,7 +337,7 @@ impl<N: Idx> RegionValues<N> {
|
||||||
end: usize,
|
end: usize,
|
||||||
) -> Option<usize> {
|
) -> Option<usize> {
|
||||||
let row = self.points.row(r)?;
|
let row = self.points.row(r)?;
|
||||||
let block = self.elements.entry_point(block);
|
let block = self.location_map.entry_point(block);
|
||||||
let start = block.plus(start);
|
let start = block.plus(start);
|
||||||
let end = block.plus(end);
|
let end = block.plus(end);
|
||||||
let first_unset = row.first_unset_in(start..=end)?;
|
let first_unset = row.first_unset_in(start..=end)?;
|
||||||
|
@ -375,8 +376,8 @@ impl<N: Idx> RegionValues<N> {
|
||||||
pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
|
pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
|
||||||
self.points.row(r).into_iter().flat_map(move |set| {
|
self.points.row(r).into_iter().flat_map(move |set| {
|
||||||
set.iter()
|
set.iter()
|
||||||
.take_while(move |&p| self.elements.point_in_range(p))
|
.take_while(move |&p| self.location_map.point_in_range(p))
|
||||||
.map(move |p| self.elements.to_location(p))
|
.map(move |p| self.location_map.to_location(p))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,12 +431,12 @@ pub(crate) trait ToElementIndex: Debug + Copy {
|
||||||
|
|
||||||
impl ToElementIndex for Location {
|
impl ToElementIndex for Location {
|
||||||
fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
|
fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
|
||||||
let index = values.elements.point_from_location(self);
|
let index = values.location_map.point_from_location(self);
|
||||||
values.points.insert(row, index)
|
values.points.insert(row, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
|
fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
|
||||||
let index = values.elements.point_from_location(self);
|
let index = values.location_map.point_from_location(self);
|
||||||
values.points.contains(row, index)
|
values.points.contains(row, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,14 +465,14 @@ impl ToElementIndex for ty::PlaceholderRegion {
|
||||||
|
|
||||||
/// For debugging purposes, returns a pretty-printed string of the given points.
|
/// For debugging purposes, returns a pretty-printed string of the given points.
|
||||||
pub(crate) fn pretty_print_points(
|
pub(crate) fn pretty_print_points(
|
||||||
elements: &DenseLocationMap,
|
location_map: &DenseLocationMap,
|
||||||
points: impl IntoIterator<Item = PointIndex>,
|
points: impl IntoIterator<Item = PointIndex>,
|
||||||
) -> String {
|
) -> String {
|
||||||
pretty_print_region_elements(
|
pretty_print_region_elements(
|
||||||
points
|
points
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.take_while(|&p| elements.point_in_range(p))
|
.take_while(|&p| location_map.point_in_range(p))
|
||||||
.map(|p| elements.to_location(p))
|
.map(|p| location_map.to_location(p))
|
||||||
.map(RegionElement::Location),
|
.map(RegionElement::Location),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ impl<'a> Iterator for AppearancesIter<'a> {
|
||||||
impl LocalUseMap {
|
impl LocalUseMap {
|
||||||
pub(crate) fn build(
|
pub(crate) fn build(
|
||||||
live_locals: &[Local],
|
live_locals: &[Local],
|
||||||
elements: &DenseLocationMap,
|
location_map: &DenseLocationMap,
|
||||||
body: &Body<'_>,
|
body: &Body<'_>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let nones = IndexVec::from_elem(None, &body.local_decls);
|
let nones = IndexVec::from_elem(None, &body.local_decls);
|
||||||
|
@ -101,7 +101,7 @@ impl LocalUseMap {
|
||||||
IndexVec::from_elem(false, &body.local_decls);
|
IndexVec::from_elem(false, &body.local_decls);
|
||||||
live_locals.iter().for_each(|&local| locals_with_use_data[local] = true);
|
live_locals.iter().for_each(|&local| locals_with_use_data[local] = true);
|
||||||
|
|
||||||
LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data }
|
LocalUseMapBuild { local_use_map: &mut local_use_map, location_map, locals_with_use_data }
|
||||||
.visit_body(body);
|
.visit_body(body);
|
||||||
|
|
||||||
local_use_map
|
local_use_map
|
||||||
|
@ -125,7 +125,7 @@ impl LocalUseMap {
|
||||||
|
|
||||||
struct LocalUseMapBuild<'me> {
|
struct LocalUseMapBuild<'me> {
|
||||||
local_use_map: &'me mut LocalUseMap,
|
local_use_map: &'me mut LocalUseMap,
|
||||||
elements: &'me DenseLocationMap,
|
location_map: &'me DenseLocationMap,
|
||||||
|
|
||||||
// Vector used in `visit_local` to signal which `Local`s do we need
|
// Vector used in `visit_local` to signal which `Local`s do we need
|
||||||
// def/use/drop information on, constructed from `live_locals` (that
|
// def/use/drop information on, constructed from `live_locals` (that
|
||||||
|
@ -147,7 +147,7 @@ impl Visitor<'_> for LocalUseMapBuild<'_> {
|
||||||
DefUse::Use => &mut self.local_use_map.first_use_at[local],
|
DefUse::Use => &mut self.local_use_map.first_use_at[local],
|
||||||
DefUse::Drop => &mut self.local_use_map.first_drop_at[local],
|
DefUse::Drop => &mut self.local_use_map.first_drop_at[local],
|
||||||
};
|
};
|
||||||
let point_index = self.elements.point_from_location(location);
|
let point_index = self.location_map.point_from_location(location);
|
||||||
let appearance_index = self
|
let appearance_index = self
|
||||||
.local_use_map
|
.local_use_map
|
||||||
.appearances
|
.appearances
|
||||||
|
|
|
@ -32,7 +32,7 @@ mod trace;
|
||||||
pub(super) fn generate<'a, 'tcx>(
|
pub(super) fn generate<'a, 'tcx>(
|
||||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
elements: &DenseLocationMap,
|
location_map: &DenseLocationMap,
|
||||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
) {
|
) {
|
||||||
|
@ -49,7 +49,7 @@ pub(super) fn generate<'a, 'tcx>(
|
||||||
trace::trace(
|
trace::trace(
|
||||||
typeck,
|
typeck,
|
||||||
body,
|
body,
|
||||||
elements,
|
location_map,
|
||||||
flow_inits,
|
flow_inits,
|
||||||
move_data,
|
move_data,
|
||||||
relevant_live_locals,
|
relevant_live_locals,
|
||||||
|
|
|
@ -37,13 +37,13 @@ use crate::type_check::{NormalizeLocation, TypeChecker};
|
||||||
pub(super) fn trace<'a, 'tcx>(
|
pub(super) fn trace<'a, 'tcx>(
|
||||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
elements: &DenseLocationMap,
|
location_map: &DenseLocationMap,
|
||||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
relevant_live_locals: Vec<Local>,
|
relevant_live_locals: Vec<Local>,
|
||||||
boring_locals: Vec<Local>,
|
boring_locals: Vec<Local>,
|
||||||
) {
|
) {
|
||||||
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);
|
let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, body);
|
||||||
|
|
||||||
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
|
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
|
||||||
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
|
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||||
|
@ -79,7 +79,7 @@ pub(super) fn trace<'a, 'tcx>(
|
||||||
typeck,
|
typeck,
|
||||||
body,
|
body,
|
||||||
flow_inits,
|
flow_inits,
|
||||||
elements,
|
location_map,
|
||||||
local_use_map,
|
local_use_map,
|
||||||
move_data,
|
move_data,
|
||||||
drop_data: FxIndexMap::default(),
|
drop_data: FxIndexMap::default(),
|
||||||
|
@ -100,7 +100,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> {
|
||||||
typeck: &'a mut TypeChecker<'typeck, 'tcx>,
|
typeck: &'a mut TypeChecker<'typeck, 'tcx>,
|
||||||
|
|
||||||
/// Defines the `PointIndex` mapping
|
/// Defines the `PointIndex` mapping
|
||||||
elements: &'a DenseLocationMap,
|
location_map: &'a DenseLocationMap,
|
||||||
|
|
||||||
/// MIR we are analyzing.
|
/// MIR we are analyzing.
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
|
@ -149,7 +149,7 @@ struct LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
|
|
||||||
impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
fn new(cx: LivenessContext<'a, 'typeck, 'b, 'tcx>) -> Self {
|
fn new(cx: LivenessContext<'a, 'typeck, 'b, 'tcx>) -> Self {
|
||||||
let num_points = cx.elements.num_points();
|
let num_points = cx.location_map.num_points();
|
||||||
LivenessResults {
|
LivenessResults {
|
||||||
cx,
|
cx,
|
||||||
defs: BitSet::new_empty(num_points),
|
defs: BitSet::new_empty(num_points),
|
||||||
|
@ -213,14 +213,14 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) {
|
fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) {
|
||||||
// This collect is more necessary than immediately apparent
|
// This collect is more necessary than immediately apparent
|
||||||
// because these facts go into `add_drop_live_facts_for()`,
|
// because these facts go into `add_drop_live_facts_for()`,
|
||||||
// which also writes to `all_facts`, and so this is genuinely
|
// which also writes to `polonius_facts`, and so this is genuinely
|
||||||
// a simultaneous overlapping mutable borrow.
|
// a simultaneous overlapping mutable borrow.
|
||||||
// FIXME for future hackers: investigate whether this is
|
// FIXME for future hackers: investigate whether this is
|
||||||
// actually necessary; these facts come from Polonius
|
// actually necessary; these facts come from Polonius
|
||||||
// and probably maybe plausibly does not need to go back in.
|
// and probably maybe plausibly does not need to go back in.
|
||||||
// It may be necessary to just pick out the parts of
|
// It may be necessary to just pick out the parts of
|
||||||
// `add_drop_live_facts_for()` that make sense.
|
// `add_drop_live_facts_for()` that make sense.
|
||||||
let Some(facts) = self.cx.typeck.all_facts.as_ref() else { return };
|
let Some(facts) = self.cx.typeck.polonius_facts.as_ref() else { return };
|
||||||
let facts_to_add: Vec<_> = {
|
let facts_to_add: Vec<_> = {
|
||||||
let relevant_live_locals: FxIndexSet<_> =
|
let relevant_live_locals: FxIndexSet<_> =
|
||||||
relevant_live_locals.iter().copied().collect();
|
relevant_live_locals.iter().copied().collect();
|
||||||
|
@ -240,7 +240,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
let live_at = IntervalSet::new(self.cx.elements.num_points());
|
let live_at = IntervalSet::new(self.cx.location_map.num_points());
|
||||||
for (local, local_ty, location) in facts_to_add {
|
for (local, local_ty, location) in facts_to_add {
|
||||||
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &live_at);
|
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &live_at);
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
// * Inclusively, the block start
|
// * Inclusively, the block start
|
||||||
// * Exclusively, the previous definition (if it's in this block)
|
// * Exclusively, the previous definition (if it's in this block)
|
||||||
// * Exclusively, the previous live_at setting (an optimization)
|
// * Exclusively, the previous live_at setting (an optimization)
|
||||||
let block_start = self.cx.elements.to_block_start(p);
|
let block_start = self.cx.location_map.to_block_start(p);
|
||||||
let previous_defs = self.defs.last_set_in(block_start..=p);
|
let previous_defs = self.defs.last_set_in(block_start..=p);
|
||||||
let previous_live_at = self.use_live_at.last_set_in(block_start..=p);
|
let previous_live_at = self.use_live_at.last_set_in(block_start..=p);
|
||||||
|
|
||||||
|
@ -303,12 +303,12 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
// terminators of predecessor basic blocks. Push those onto the
|
// terminators of predecessor basic blocks. Push those onto the
|
||||||
// stack so that the next iteration(s) will process them.
|
// stack so that the next iteration(s) will process them.
|
||||||
|
|
||||||
let block = self.cx.elements.to_location(block_start).block;
|
let block = self.cx.location_map.to_location(block_start).block;
|
||||||
self.stack.extend(
|
self.stack.extend(
|
||||||
self.cx.body.basic_blocks.predecessors()[block]
|
self.cx.body.basic_blocks.predecessors()[block]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
|
.map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
|
||||||
.map(|pred_loc| self.cx.elements.point_from_location(pred_loc)),
|
.map(|pred_loc| self.cx.location_map.point_from_location(pred_loc)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,7 +331,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
|
|
||||||
// Find the drops where `local` is initialized.
|
// Find the drops where `local` is initialized.
|
||||||
for drop_point in self.cx.local_use_map.drops(local) {
|
for drop_point in self.cx.local_use_map.drops(local) {
|
||||||
let location = self.cx.elements.to_location(drop_point);
|
let location = self.cx.location_map.to_location(drop_point);
|
||||||
debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,);
|
debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,);
|
||||||
|
|
||||||
if self.cx.initialized_at_terminator(location.block, mpi)
|
if self.cx.initialized_at_terminator(location.block, mpi)
|
||||||
|
@ -367,7 +367,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
debug!(
|
debug!(
|
||||||
"compute_drop_live_points_for_block(mpi={:?}, term_point={:?})",
|
"compute_drop_live_points_for_block(mpi={:?}, term_point={:?})",
|
||||||
self.cx.move_data.move_paths[mpi].place,
|
self.cx.move_data.move_paths[mpi].place,
|
||||||
self.cx.elements.to_location(term_point),
|
self.cx.location_map.to_location(term_point),
|
||||||
);
|
);
|
||||||
|
|
||||||
// We are only invoked with terminators where `mpi` is
|
// We are only invoked with terminators where `mpi` is
|
||||||
|
@ -377,12 +377,15 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
// Otherwise, scan backwards through the statements in the
|
// Otherwise, scan backwards through the statements in the
|
||||||
// block. One of them may be either a definition or use
|
// block. One of them may be either a definition or use
|
||||||
// live point.
|
// live point.
|
||||||
let term_location = self.cx.elements.to_location(term_point);
|
let term_location = self.cx.location_map.to_location(term_point);
|
||||||
debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,);
|
debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,);
|
||||||
let block = term_location.block;
|
let block = term_location.block;
|
||||||
let entry_point = self.cx.elements.entry_point(term_location.block);
|
let entry_point = self.cx.location_map.entry_point(term_location.block);
|
||||||
for p in (entry_point..term_point).rev() {
|
for p in (entry_point..term_point).rev() {
|
||||||
debug!("compute_drop_live_points_for_block: p = {:?}", self.cx.elements.to_location(p));
|
debug!(
|
||||||
|
"compute_drop_live_points_for_block: p = {:?}",
|
||||||
|
self.cx.location_map.to_location(p)
|
||||||
|
);
|
||||||
|
|
||||||
if self.defs.contains(p) {
|
if self.defs.contains(p) {
|
||||||
debug!("compute_drop_live_points_for_block: def site");
|
debug!("compute_drop_live_points_for_block: def site");
|
||||||
|
@ -428,7 +431,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let pred_term_loc = self.cx.body.terminator_loc(pred_block);
|
let pred_term_loc = self.cx.body.terminator_loc(pred_block);
|
||||||
let pred_term_point = self.cx.elements.point_from_location(pred_term_loc);
|
let pred_term_point = self.cx.location_map.point_from_location(pred_term_loc);
|
||||||
|
|
||||||
// If the terminator of this predecessor either *assigns*
|
// If the terminator of this predecessor either *assigns*
|
||||||
// our value or is a "normal use", then stop.
|
// our value or is a "normal use", then stop.
|
||||||
|
@ -523,7 +526,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
||||||
/// points `live_at`.
|
/// points `live_at`.
|
||||||
fn add_use_live_facts_for(&mut self, value: Ty<'tcx>, live_at: &IntervalSet<PointIndex>) {
|
fn add_use_live_facts_for(&mut self, value: Ty<'tcx>, live_at: &IntervalSet<PointIndex>) {
|
||||||
debug!("add_use_live_facts_for(value={:?})", value);
|
debug!("add_use_live_facts_for(value={:?})", value);
|
||||||
Self::make_all_regions_live(self.elements, self.typeck, value, live_at);
|
Self::make_all_regions_live(self.location_map, self.typeck, value, live_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Some variable with type `live_ty` is "drop live" at `location`
|
/// Some variable with type `live_ty` is "drop live" at `location`
|
||||||
|
@ -547,7 +550,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
||||||
dropped_local,
|
dropped_local,
|
||||||
dropped_ty,
|
dropped_ty,
|
||||||
drop_locations,
|
drop_locations,
|
||||||
values::pretty_print_points(self.elements, live_at.iter()),
|
values::pretty_print_points(self.location_map, live_at.iter()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
|
let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
|
||||||
|
@ -574,19 +577,19 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
||||||
// All things in the `outlives` array may be touched by
|
// All things in the `outlives` array may be touched by
|
||||||
// the destructor and must be live at this point.
|
// the destructor and must be live at this point.
|
||||||
for &kind in &drop_data.dropck_result.kinds {
|
for &kind in &drop_data.dropck_result.kinds {
|
||||||
Self::make_all_regions_live(self.elements, self.typeck, kind, live_at);
|
Self::make_all_regions_live(self.location_map, self.typeck, kind, live_at);
|
||||||
polonius::legacy::emit_drop_facts(
|
polonius::legacy::emit_drop_facts(
|
||||||
self.typeck.tcx(),
|
self.typeck.tcx(),
|
||||||
dropped_local,
|
dropped_local,
|
||||||
&kind,
|
&kind,
|
||||||
self.typeck.universal_regions,
|
self.typeck.universal_regions,
|
||||||
self.typeck.all_facts,
|
self.typeck.polonius_facts,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_all_regions_live(
|
fn make_all_regions_live(
|
||||||
elements: &DenseLocationMap,
|
location_map: &DenseLocationMap,
|
||||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||||
value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
|
value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
|
||||||
live_at: &IntervalSet<PointIndex>,
|
live_at: &IntervalSet<PointIndex>,
|
||||||
|
@ -594,7 +597,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
||||||
debug!("make_all_regions_live(value={:?})", value);
|
debug!("make_all_regions_live(value={:?})", value);
|
||||||
debug!(
|
debug!(
|
||||||
"make_all_regions_live: live_at={}",
|
"make_all_regions_live: live_at={}",
|
||||||
values::pretty_print_points(elements, live_at.iter()),
|
values::pretty_print_points(location_map, live_at.iter()),
|
||||||
);
|
);
|
||||||
|
|
||||||
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
|
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
|
||||||
|
|
|
@ -49,7 +49,7 @@ use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
|
||||||
use crate::diagnostics::UniverseInfo;
|
use crate::diagnostics::UniverseInfo;
|
||||||
use crate::member_constraints::MemberConstraintSet;
|
use crate::member_constraints::MemberConstraintSet;
|
||||||
use crate::polonius::PoloniusContext;
|
use crate::polonius::PoloniusContext;
|
||||||
use crate::polonius::legacy::{AllFacts, LocationTable};
|
use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable};
|
||||||
use crate::region_infer::TypeTest;
|
use crate::region_infer::TypeTest;
|
||||||
use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
|
use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
|
||||||
use crate::renumber::RegionCtxt;
|
use crate::renumber::RegionCtxt;
|
||||||
|
@ -98,29 +98,29 @@ mod relate_tys;
|
||||||
/// - `body` -- MIR body to type-check
|
/// - `body` -- MIR body to type-check
|
||||||
/// - `promoted` -- map of promoted constants within `body`
|
/// - `promoted` -- map of promoted constants within `body`
|
||||||
/// - `universal_regions` -- the universal regions from `body`s function signature
|
/// - `universal_regions` -- the universal regions from `body`s function signature
|
||||||
/// - `location_table` -- MIR location map of `body`
|
/// - `location_table` -- for datalog polonius, the map between `Location`s and `RichLocation`s
|
||||||
/// - `borrow_set` -- information about borrows occurring in `body`
|
/// - `borrow_set` -- information about borrows occurring in `body`
|
||||||
/// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts
|
/// - `polonius_facts` -- when using Polonius, this is the generated set of Polonius facts
|
||||||
/// - `flow_inits` -- results of a maybe-init dataflow analysis
|
/// - `flow_inits` -- results of a maybe-init dataflow analysis
|
||||||
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
|
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
|
||||||
/// - `elements` -- MIR region map
|
/// - `location_map` -- map between MIR `Location` and `PointIndex`
|
||||||
pub(crate) fn type_check<'a, 'tcx>(
|
pub(crate) fn type_check<'a, 'tcx>(
|
||||||
infcx: &BorrowckInferCtxt<'tcx>,
|
infcx: &BorrowckInferCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||||
universal_regions: UniversalRegions<'tcx>,
|
universal_regions: UniversalRegions<'tcx>,
|
||||||
location_table: &LocationTable,
|
location_table: &PoloniusLocationTable,
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
all_facts: &mut Option<AllFacts>,
|
polonius_facts: &mut Option<PoloniusFacts>,
|
||||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||||
move_data: &MoveData<'tcx>,
|
move_data: &MoveData<'tcx>,
|
||||||
elements: Rc<DenseLocationMap>,
|
location_map: Rc<DenseLocationMap>,
|
||||||
) -> MirTypeckResults<'tcx> {
|
) -> MirTypeckResults<'tcx> {
|
||||||
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
||||||
let mut constraints = MirTypeckRegionConstraints {
|
let mut constraints = MirTypeckRegionConstraints {
|
||||||
placeholder_indices: PlaceholderIndices::default(),
|
placeholder_indices: PlaceholderIndices::default(),
|
||||||
placeholder_index_to_region: IndexVec::default(),
|
placeholder_index_to_region: IndexVec::default(),
|
||||||
liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&elements)),
|
liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&location_map)),
|
||||||
outlives_constraints: OutlivesConstraintSet::default(),
|
outlives_constraints: OutlivesConstraintSet::default(),
|
||||||
member_constraints: MemberConstraintSet::default(),
|
member_constraints: MemberConstraintSet::default(),
|
||||||
type_tests: Vec::default(),
|
type_tests: Vec::default(),
|
||||||
|
@ -165,7 +165,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
||||||
reported_errors: Default::default(),
|
reported_errors: Default::default(),
|
||||||
universal_regions: &universal_region_relations.universal_regions,
|
universal_regions: &universal_region_relations.universal_regions,
|
||||||
location_table,
|
location_table,
|
||||||
all_facts,
|
polonius_facts,
|
||||||
borrow_set,
|
borrow_set,
|
||||||
constraints: &mut constraints,
|
constraints: &mut constraints,
|
||||||
polonius_context: &mut polonius_context,
|
polonius_context: &mut polonius_context,
|
||||||
|
@ -180,7 +180,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
||||||
typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output);
|
typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output);
|
||||||
typeck.check_signature_annotation(body);
|
typeck.check_signature_annotation(body);
|
||||||
|
|
||||||
liveness::generate(&mut typeck, body, &elements, flow_inits, move_data);
|
liveness::generate(&mut typeck, body, &location_map, flow_inits, move_data);
|
||||||
|
|
||||||
let opaque_type_values =
|
let opaque_type_values =
|
||||||
opaque_types::take_opaques_and_register_member_constraints(&mut typeck);
|
opaque_types::take_opaques_and_register_member_constraints(&mut typeck);
|
||||||
|
@ -495,14 +495,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
|
|
||||||
// Use new sets of constraints and closure bounds so that we can
|
// Use new sets of constraints and closure bounds so that we can
|
||||||
// modify their locations.
|
// modify their locations.
|
||||||
let all_facts = &mut None;
|
let polonius_facts = &mut None;
|
||||||
let mut constraints = Default::default();
|
let mut constraints = Default::default();
|
||||||
let mut liveness_constraints =
|
let mut liveness_constraints =
|
||||||
LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body)));
|
LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body)));
|
||||||
// Don't try to add borrow_region facts for the promoted MIR
|
// Don't try to add borrow_region facts for the promoted MIR
|
||||||
|
|
||||||
let mut swap_constraints = |this: &mut Self| {
|
let mut swap_constraints = |this: &mut Self| {
|
||||||
mem::swap(this.typeck.all_facts, all_facts);
|
mem::swap(this.typeck.polonius_facts, polonius_facts);
|
||||||
mem::swap(&mut this.typeck.constraints.outlives_constraints, &mut constraints);
|
mem::swap(&mut this.typeck.constraints.outlives_constraints, &mut constraints);
|
||||||
mem::swap(&mut this.typeck.constraints.liveness_constraints, &mut liveness_constraints);
|
mem::swap(&mut this.typeck.constraints.liveness_constraints, &mut liveness_constraints);
|
||||||
};
|
};
|
||||||
|
@ -560,8 +560,8 @@ struct TypeChecker<'a, 'tcx> {
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||||
universal_regions: &'a UniversalRegions<'tcx>,
|
universal_regions: &'a UniversalRegions<'tcx>,
|
||||||
location_table: &'a LocationTable,
|
location_table: &'a PoloniusLocationTable,
|
||||||
all_facts: &'a mut Option<AllFacts>,
|
polonius_facts: &'a mut Option<PoloniusFacts>,
|
||||||
borrow_set: &'a BorrowSet<'tcx>,
|
borrow_set: &'a BorrowSet<'tcx>,
|
||||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||||
/// When using `-Zpolonius=next`, the helper data used to create polonius constraints.
|
/// When using `-Zpolonius=next`, the helper data used to create polonius constraints.
|
||||||
|
@ -2341,18 +2341,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
borrowed_place: &Place<'tcx>,
|
borrowed_place: &Place<'tcx>,
|
||||||
) {
|
) {
|
||||||
// These constraints are only meaningful during borrowck:
|
// These constraints are only meaningful during borrowck:
|
||||||
let Self { borrow_set, location_table, all_facts, constraints, .. } = self;
|
let Self { borrow_set, location_table, polonius_facts, constraints, .. } = self;
|
||||||
|
|
||||||
// In Polonius mode, we also push a `loan_issued_at` fact
|
// In Polonius mode, we also push a `loan_issued_at` fact
|
||||||
// linking the loan to the region (in some cases, though,
|
// linking the loan to the region (in some cases, though,
|
||||||
// there is no loan associated with this borrow expression --
|
// there is no loan associated with this borrow expression --
|
||||||
// that occurs when we are borrowing an unsafe place, for
|
// that occurs when we are borrowing an unsafe place, for
|
||||||
// example).
|
// example).
|
||||||
if let Some(all_facts) = all_facts {
|
if let Some(polonius_facts) = polonius_facts {
|
||||||
let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
||||||
if let Some(borrow_index) = borrow_set.get_index_of(&location) {
|
if let Some(borrow_index) = borrow_set.get_index_of(&location) {
|
||||||
let region_vid = borrow_region.as_var();
|
let region_vid = borrow_region.as_var();
|
||||||
all_facts.loan_issued_at.push((
|
polonius_facts.loan_issued_at.push((
|
||||||
region_vid.into(),
|
region_vid.into(),
|
||||||
borrow_index,
|
borrow_index,
|
||||||
location_table.mid_index(location),
|
location_table.mid_index(location),
|
||||||
|
|
|
@ -522,7 +522,7 @@ impl MacResult for MacEager {
|
||||||
return Some(P(ast::Pat {
|
return Some(P(ast::Pat {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
span: e.span,
|
span: e.span,
|
||||||
kind: PatKind::Lit(e),
|
kind: PatKind::Expr(e),
|
||||||
tokens: None,
|
tokens: None,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -486,7 +486,7 @@ impl<'a> ExtCtxt<'a> {
|
||||||
self.pat(span, PatKind::Wild)
|
self.pat(span, PatKind::Wild)
|
||||||
}
|
}
|
||||||
pub fn pat_lit(&self, span: Span, expr: P<ast::Expr>) -> P<ast::Pat> {
|
pub fn pat_lit(&self, span: Span, expr: P<ast::Expr>) -> P<ast::Pat> {
|
||||||
self.pat(span, PatKind::Lit(expr))
|
self.pat(span, PatKind::Expr(expr))
|
||||||
}
|
}
|
||||||
pub fn pat_ident(&self, span: Span, ident: Ident) -> P<ast::Pat> {
|
pub fn pat_ident(&self, span: Span, ident: Ident) -> P<ast::Pat> {
|
||||||
self.pat_ident_binding_mode(span, ident, ast::BindingMode::NONE)
|
self.pat_ident_binding_mode(span, ident, ast::BindingMode::NONE)
|
||||||
|
|
|
@ -1386,7 +1386,7 @@ impl<'hir> Pat<'hir> {
|
||||||
|
|
||||||
use PatKind::*;
|
use PatKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
|
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
|
||||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
|
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
|
||||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||||
|
@ -1413,7 +1413,7 @@ impl<'hir> Pat<'hir> {
|
||||||
|
|
||||||
use PatKind::*;
|
use PatKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
|
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
|
||||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
||||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||||
|
@ -1519,6 +1519,26 @@ impl fmt::Debug for DotDotPos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
|
pub struct PatExpr<'hir> {
|
||||||
|
pub hir_id: HirId,
|
||||||
|
pub span: Span,
|
||||||
|
pub kind: PatExprKind<'hir>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
|
pub enum PatExprKind<'hir> {
|
||||||
|
Lit {
|
||||||
|
lit: &'hir Lit,
|
||||||
|
// FIXME: move this into `Lit` and handle negated literal expressions
|
||||||
|
// once instead of matching on unop neg expressions everywhere.
|
||||||
|
negated: bool,
|
||||||
|
},
|
||||||
|
ConstBlock(ConstBlock),
|
||||||
|
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
|
||||||
|
Path(QPath<'hir>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
pub enum PatKind<'hir> {
|
pub enum PatKind<'hir> {
|
||||||
/// Represents a wildcard pattern (i.e., `_`).
|
/// Represents a wildcard pattern (i.e., `_`).
|
||||||
|
@ -1563,14 +1583,14 @@ pub enum PatKind<'hir> {
|
||||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||||
Ref(&'hir Pat<'hir>, Mutability),
|
Ref(&'hir Pat<'hir>, Mutability),
|
||||||
|
|
||||||
/// A literal.
|
/// A literal, const block or path.
|
||||||
Lit(&'hir Expr<'hir>),
|
Expr(&'hir PatExpr<'hir>),
|
||||||
|
|
||||||
/// A guard pattern (e.g., `x if guard(x)`).
|
/// A guard pattern (e.g., `x if guard(x)`).
|
||||||
Guard(&'hir Pat<'hir>, &'hir Expr<'hir>),
|
Guard(&'hir Pat<'hir>, &'hir Expr<'hir>),
|
||||||
|
|
||||||
/// A range pattern (e.g., `1..=2` or `1..2`).
|
/// A range pattern (e.g., `1..=2` or `1..2`).
|
||||||
Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd),
|
Range(Option<&'hir PatExpr<'hir>>, Option<&'hir PatExpr<'hir>>, RangeEnd),
|
||||||
|
|
||||||
/// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
|
/// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
|
||||||
///
|
///
|
||||||
|
@ -4144,6 +4164,10 @@ pub enum Node<'hir> {
|
||||||
OpaqueTy(&'hir OpaqueTy<'hir>),
|
OpaqueTy(&'hir OpaqueTy<'hir>),
|
||||||
Pat(&'hir Pat<'hir>),
|
Pat(&'hir Pat<'hir>),
|
||||||
PatField(&'hir PatField<'hir>),
|
PatField(&'hir PatField<'hir>),
|
||||||
|
/// Needed as its own node with its own HirId for tracking
|
||||||
|
/// the unadjusted type of literals within patterns
|
||||||
|
/// (e.g. byte str literals not being of slice type).
|
||||||
|
PatExpr(&'hir PatExpr<'hir>),
|
||||||
Arm(&'hir Arm<'hir>),
|
Arm(&'hir Arm<'hir>),
|
||||||
Block(&'hir Block<'hir>),
|
Block(&'hir Block<'hir>),
|
||||||
LetStmt(&'hir LetStmt<'hir>),
|
LetStmt(&'hir LetStmt<'hir>),
|
||||||
|
@ -4200,6 +4224,7 @@ impl<'hir> Node<'hir> {
|
||||||
| Node::Block(..)
|
| Node::Block(..)
|
||||||
| Node::Ctor(..)
|
| Node::Ctor(..)
|
||||||
| Node::Pat(..)
|
| Node::Pat(..)
|
||||||
|
| Node::PatExpr(..)
|
||||||
| Node::Arm(..)
|
| Node::Arm(..)
|
||||||
| Node::LetStmt(..)
|
| Node::LetStmt(..)
|
||||||
| Node::Crate(..)
|
| Node::Crate(..)
|
||||||
|
|
|
@ -342,6 +342,9 @@ pub trait Visitor<'v>: Sized {
|
||||||
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
|
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
|
||||||
walk_pat_field(self, f)
|
walk_pat_field(self, f)
|
||||||
}
|
}
|
||||||
|
fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result {
|
||||||
|
walk_pat_expr(self, expr)
|
||||||
|
}
|
||||||
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
|
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
|
||||||
walk_anon_const(self, c)
|
walk_anon_const(self, c)
|
||||||
}
|
}
|
||||||
|
@ -685,10 +688,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
|
||||||
try_visit!(visitor.visit_ident(ident));
|
try_visit!(visitor.visit_ident(ident));
|
||||||
visit_opt!(visitor, visit_pat, optional_subpattern);
|
visit_opt!(visitor, visit_pat, optional_subpattern);
|
||||||
}
|
}
|
||||||
PatKind::Lit(ref expression) => try_visit!(visitor.visit_expr(expression)),
|
PatKind::Expr(ref expression) => try_visit!(visitor.visit_pat_expr(expression)),
|
||||||
PatKind::Range(ref lower_bound, ref upper_bound, _) => {
|
PatKind::Range(ref lower_bound, ref upper_bound, _) => {
|
||||||
visit_opt!(visitor, visit_expr, lower_bound);
|
visit_opt!(visitor, visit_pat_expr, lower_bound);
|
||||||
visit_opt!(visitor, visit_expr, upper_bound);
|
visit_opt!(visitor, visit_pat_expr, upper_bound);
|
||||||
}
|
}
|
||||||
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
|
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
|
||||||
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
|
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
|
||||||
|
@ -710,6 +713,15 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
|
||||||
visitor.visit_pat(field.pat)
|
visitor.visit_pat(field.pat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result {
|
||||||
|
try_visit!(visitor.visit_id(expr.hir_id));
|
||||||
|
match &expr.kind {
|
||||||
|
PatExprKind::Lit { .. } => V::Result::output(),
|
||||||
|
PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c),
|
||||||
|
PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result {
|
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result {
|
||||||
try_visit!(visitor.visit_id(constant.hir_id));
|
try_visit!(visitor.visit_id(constant.hir_id));
|
||||||
visitor.visit_nested_body(constant.body)
|
visitor.visit_nested_body(constant.body)
|
||||||
|
|
|
@ -704,7 +704,7 @@ fn resolve_local<'tcx>(
|
||||||
| PatKind::Wild
|
| PatKind::Wild
|
||||||
| PatKind::Never
|
| PatKind::Never
|
||||||
| PatKind::Path(_)
|
| PatKind::Path(_)
|
||||||
| PatKind::Lit(_)
|
| PatKind::Expr(_)
|
||||||
| PatKind::Range(_, _, _)
|
| PatKind::Range(_, _, _)
|
||||||
| PatKind::Err(_) => false,
|
| PatKind::Err(_) => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2449,17 +2449,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
Ty::new_error(tcx, err)
|
Ty::new_error(tcx, err)
|
||||||
}
|
}
|
||||||
hir::PatKind::Range(start, end, include_end) => {
|
hir::PatKind::Range(start, end, include_end) => {
|
||||||
let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> {
|
let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
|
||||||
let (expr, neg) = match expr.kind {
|
let (c, c_ty) = match expr.kind {
|
||||||
hir::ExprKind::Unary(hir::UnOp::Neg, negated) => {
|
hir::PatExprKind::Lit { lit, negated } => {
|
||||||
(negated, Some((expr.hir_id, expr.span)))
|
|
||||||
}
|
|
||||||
_ => (expr, None),
|
|
||||||
};
|
|
||||||
let (c, c_ty) = match &expr.kind {
|
|
||||||
hir::ExprKind::Lit(lit) => {
|
|
||||||
let lit_input =
|
let lit_input =
|
||||||
LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() };
|
LitToConstInput { lit: &lit.node, ty, neg: negated };
|
||||||
let ct = match tcx.lit_to_const(lit_input) {
|
let ct = match tcx.lit_to_const(lit_input) {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(LitToConstError::Reported(err)) => {
|
Err(LitToConstError::Reported(err)) => {
|
||||||
|
@ -2470,17 +2464,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
(ct, ty)
|
(ct, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
hir::PatExprKind::Path(hir::QPath::Resolved(
|
||||||
_,
|
_,
|
||||||
path @ &hir::Path {
|
path @ &hir::Path {
|
||||||
res: Res::Def(DefKind::ConstParam, def_id),
|
res: Res::Def(DefKind::ConstParam, def_id),
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
)) => {
|
)) => {
|
||||||
let _ = self.prohibit_generic_args(
|
match self.prohibit_generic_args(
|
||||||
path.segments.iter(),
|
path.segments.iter(),
|
||||||
GenericsArgsErrExtend::Param(def_id),
|
GenericsArgsErrExtend::Param(def_id),
|
||||||
);
|
) {
|
||||||
|
Ok(()) => {
|
||||||
let ty = tcx
|
let ty = tcx
|
||||||
.type_of(def_id)
|
.type_of(def_id)
|
||||||
.no_bound_vars()
|
.no_bound_vars()
|
||||||
|
@ -2488,6 +2483,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
let ct = self.lower_const_param(def_id, expr.hir_id);
|
let ct = self.lower_const_param(def_id, expr.hir_id);
|
||||||
(ct, ty)
|
(ct, ty)
|
||||||
}
|
}
|
||||||
|
Err(guar) => (
|
||||||
|
ty::Const::new_error(tcx, guar),
|
||||||
|
Ty::new_error(tcx, guar),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let err = tcx
|
let err = tcx
|
||||||
|
@ -2497,9 +2498,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.record_ty(expr.hir_id, c_ty, expr.span);
|
self.record_ty(expr.hir_id, c_ty, expr.span);
|
||||||
if let Some((id, span)) = neg {
|
|
||||||
self.record_ty(id, c_ty, span);
|
|
||||||
}
|
|
||||||
c
|
c
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -199,6 +199,7 @@ impl<'a> State<'a> {
|
||||||
Node::OpaqueTy(o) => self.print_opaque_ty(o),
|
Node::OpaqueTy(o) => self.print_opaque_ty(o),
|
||||||
Node::Pat(a) => self.print_pat(a),
|
Node::Pat(a) => self.print_pat(a),
|
||||||
Node::PatField(a) => self.print_patfield(a),
|
Node::PatField(a) => self.print_patfield(a),
|
||||||
|
Node::PatExpr(a) => self.print_pat_expr(a),
|
||||||
Node::Arm(a) => self.print_arm(a),
|
Node::Arm(a) => self.print_arm(a),
|
||||||
Node::Infer(_) => self.word("_"),
|
Node::Infer(_) => self.word("_"),
|
||||||
Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident),
|
Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident),
|
||||||
|
@ -1849,6 +1850,19 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_pat_expr(&mut self, expr: &hir::PatExpr<'_>) {
|
||||||
|
match &expr.kind {
|
||||||
|
hir::PatExprKind::Lit { lit, negated } => {
|
||||||
|
if *negated {
|
||||||
|
self.word("-");
|
||||||
|
}
|
||||||
|
self.print_literal(lit);
|
||||||
|
}
|
||||||
|
hir::PatExprKind::ConstBlock(c) => self.print_inline_const(c),
|
||||||
|
hir::PatExprKind::Path(qpath) => self.print_qpath(qpath, true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
|
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
|
||||||
self.maybe_print_comment(pat.span.lo());
|
self.maybe_print_comment(pat.span.lo());
|
||||||
self.ann.pre(self, AnnNode::Pat(pat));
|
self.ann.pre(self, AnnNode::Pat(pat));
|
||||||
|
@ -1966,17 +1980,17 @@ impl<'a> State<'a> {
|
||||||
self.pclose();
|
self.pclose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Lit(e) => self.print_expr(e),
|
PatKind::Expr(e) => self.print_pat_expr(e),
|
||||||
PatKind::Range(begin, end, end_kind) => {
|
PatKind::Range(begin, end, end_kind) => {
|
||||||
if let Some(expr) = begin {
|
if let Some(expr) = begin {
|
||||||
self.print_expr(expr);
|
self.print_pat_expr(expr);
|
||||||
}
|
}
|
||||||
match end_kind {
|
match end_kind {
|
||||||
RangeEnd::Included => self.word("..."),
|
RangeEnd::Included => self.word("..."),
|
||||||
RangeEnd::Excluded => self.word(".."),
|
RangeEnd::Excluded => self.word(".."),
|
||||||
}
|
}
|
||||||
if let Some(expr) = end {
|
if let Some(expr) = end {
|
||||||
self.print_expr(expr);
|
self.print_pat_expr(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Slice(before, slice, after) => {
|
PatKind::Slice(before, slice, after) => {
|
||||||
|
|
|
@ -430,6 +430,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
| hir::Node::AssocItemConstraint(_)
|
| hir::Node::AssocItemConstraint(_)
|
||||||
| hir::Node::TraitRef(_)
|
| hir::Node::TraitRef(_)
|
||||||
| hir::Node::PatField(_)
|
| hir::Node::PatField(_)
|
||||||
|
| hir::Node::PatExpr(_)
|
||||||
| hir::Node::LetStmt(_)
|
| hir::Node::LetStmt(_)
|
||||||
| hir::Node::Synthetic
|
| hir::Node::Synthetic
|
||||||
| hir::Node::Err(_)
|
| hir::Node::Err(_)
|
||||||
|
@ -484,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
| hir::PatKind::Box(_)
|
| hir::PatKind::Box(_)
|
||||||
| hir::PatKind::Ref(_, _)
|
| hir::PatKind::Ref(_, _)
|
||||||
| hir::PatKind::Deref(_)
|
| hir::PatKind::Deref(_)
|
||||||
| hir::PatKind::Lit(_)
|
| hir::PatKind::Expr(_)
|
||||||
| hir::PatKind::Range(_, _, _)
|
| hir::PatKind::Range(_, _, _)
|
||||||
| hir::PatKind::Slice(_, _, _)
|
| hir::PatKind::Slice(_, _, _)
|
||||||
| hir::PatKind::Err(_) => true,
|
| hir::PatKind::Err(_) => true,
|
||||||
|
@ -837,7 +838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// We always require that the type provided as the value for
|
// We always require that the type provided as the value for
|
||||||
// a type parameter outlives the moment of instantiation.
|
// a type parameter outlives the moment of instantiation.
|
||||||
let args = self.typeck_results.borrow().node_args(expr.hir_id);
|
let args = self.typeck_results.borrow().node_args(expr.hir_id);
|
||||||
self.add_wf_bounds(args, expr);
|
self.add_wf_bounds(args, expr.span);
|
||||||
|
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
@ -1796,7 +1797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr_const_block(
|
pub(super) fn check_expr_const_block(
|
||||||
&self,
|
&self,
|
||||||
block: &'tcx hir::ConstBlock,
|
block: &'tcx hir::ConstBlock,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
|
|
|
@ -595,7 +595,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
let place_ty = place.place.ty();
|
let place_ty = place.place.ty();
|
||||||
needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
|
needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
|
||||||
}
|
}
|
||||||
PatKind::Lit(_) | PatKind::Range(..) => {
|
PatKind::Expr(_) | PatKind::Range(..) => {
|
||||||
// If the PatKind is a Lit or a Range then we want
|
// If the PatKind is a Lit or a Range then we want
|
||||||
// to borrow discr.
|
// to borrow discr.
|
||||||
needs_to_be_read = true;
|
needs_to_be_read = true;
|
||||||
|
@ -1803,7 +1803,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
|
|
||||||
PatKind::Path(_)
|
PatKind::Path(_)
|
||||||
| PatKind::Binding(.., None)
|
| PatKind::Binding(.., None)
|
||||||
| PatKind::Lit(..)
|
| PatKind::Expr(..)
|
||||||
| PatKind::Range(..)
|
| PatKind::Range(..)
|
||||||
| PatKind::Never
|
| PatKind::Never
|
||||||
| PatKind::Wild
|
| PatKind::Wild
|
||||||
|
|
|
@ -577,11 +577,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers obligations that all `args` are well-formed.
|
/// Registers obligations that all `args` are well-formed.
|
||||||
pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &hir::Expr<'_>) {
|
pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, span: Span) {
|
||||||
for arg in args.iter().filter(|arg| {
|
for arg in args.iter().filter(|arg| {
|
||||||
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
|
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
|
||||||
}) {
|
}) {
|
||||||
self.register_wf_obligation(arg, expr.span, ObligationCauseCode::WellFormed(None));
|
self.register_wf_obligation(arg, span, ObligationCauseCode::WellFormed(None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1039,6 +1039,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
def_id,
|
def_id,
|
||||||
span,
|
span,
|
||||||
),
|
),
|
||||||
|
Res::Err => {
|
||||||
|
return (
|
||||||
|
Ty::new_error(
|
||||||
|
tcx,
|
||||||
|
tcx.dcx().span_delayed_bug(span, "could not resolve path {:?}"),
|
||||||
|
),
|
||||||
|
res,
|
||||||
|
);
|
||||||
|
}
|
||||||
_ => bug!("instantiate_value_path on {:?}", res),
|
_ => bug!("instantiate_value_path on {:?}", res),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -611,7 +611,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||||
|
|
||||||
// this is a projection from a trait reference, so we have to
|
// this is a projection from a trait reference, so we have to
|
||||||
// make sure that the trait reference inputs are well-formed.
|
// make sure that the trait reference inputs are well-formed.
|
||||||
self.add_wf_bounds(all_args, self.call_expr);
|
self.add_wf_bounds(all_args, self.call_expr.span);
|
||||||
|
|
||||||
// the function type must also be well-formed (this is not
|
// the function type must also be well-formed (this is not
|
||||||
// implied by the args being well-formed because of inherent
|
// implied by the args being well-formed because of inherent
|
||||||
|
|
|
@ -170,6 +170,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
span,
|
span,
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
|
| hir::Node::PatExpr(&hir::PatExpr {
|
||||||
|
kind: hir::PatExprKind::Path(QPath::TypeRelative(rcvr, segment)),
|
||||||
|
span,
|
||||||
|
..
|
||||||
|
})
|
||||||
| hir::Node::Pat(&hir::Pat {
|
| hir::Node::Pat(&hir::Pat {
|
||||||
kind:
|
kind:
|
||||||
hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))
|
hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))
|
||||||
|
|
|
@ -30,6 +30,7 @@ use tracing::{debug, instrument, trace};
|
||||||
use ty::VariantDef;
|
use ty::VariantDef;
|
||||||
|
|
||||||
use super::report_unexpected_variant_res;
|
use super::report_unexpected_variant_res;
|
||||||
|
use crate::expectation::Expectation;
|
||||||
use crate::gather_locals::DeclOrigin;
|
use crate::gather_locals::DeclOrigin;
|
||||||
use crate::{FnCtxt, LoweredTy, errors};
|
use crate::{FnCtxt, LoweredTy, errors};
|
||||||
|
|
||||||
|
@ -270,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
PatKind::Wild | PatKind::Err(_) => expected,
|
PatKind::Wild | PatKind::Err(_) => expected,
|
||||||
// We allow any type here; we ensure that the type is uninhabited during match checking.
|
// We allow any type here; we ensure that the type is uninhabited during match checking.
|
||||||
PatKind::Never => expected,
|
PatKind::Never => expected,
|
||||||
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
||||||
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
||||||
PatKind::Binding(ba, var_id, ident, sub) => {
|
PatKind::Binding(ba, var_id, ident, sub) => {
|
||||||
self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
|
self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
|
||||||
|
@ -279,7 +280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
|
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
|
||||||
}
|
}
|
||||||
PatKind::Path(ref qpath) => {
|
PatKind::Path(ref qpath) => {
|
||||||
self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti)
|
self.check_pat_path(pat.hir_id, pat.span, qpath, path_res.unwrap(), expected, ti)
|
||||||
}
|
}
|
||||||
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
|
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
|
||||||
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
|
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
|
||||||
|
@ -398,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
|
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
|
||||||
//
|
//
|
||||||
// Call `resolve_vars_if_possible` here for inline const blocks.
|
// Call `resolve_vars_if_possible` here for inline const blocks.
|
||||||
PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
|
PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
|
||||||
ty::Ref(..) => AdjustMode::Pass,
|
ty::Ref(..) => AdjustMode::Pass,
|
||||||
_ => AdjustMode::Peel,
|
_ => AdjustMode::Peel,
|
||||||
},
|
},
|
||||||
|
@ -493,10 +494,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
(expected, def_br, max_ref_mutbl)
|
(expected, def_br, max_ref_mutbl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
|
||||||
|
let ty = match <.kind {
|
||||||
|
rustc_hir::PatExprKind::Lit { lit, .. } => {
|
||||||
|
self.check_expr_lit(lit, Expectation::NoExpectation)
|
||||||
|
}
|
||||||
|
rustc_hir::PatExprKind::ConstBlock(c) => {
|
||||||
|
self.check_expr_const_block(c, Expectation::NoExpectation)
|
||||||
|
}
|
||||||
|
rustc_hir::PatExprKind::Path(qpath) => {
|
||||||
|
let (res, opt_ty, segments) =
|
||||||
|
self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
|
||||||
|
self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.write_ty(lt.hir_id, ty);
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
|
||||||
fn check_pat_lit(
|
fn check_pat_lit(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
lt: &hir::Expr<'tcx>,
|
lt: &hir::PatExpr<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
ti: &TopInfo<'tcx>,
|
ti: &TopInfo<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
|
@ -507,7 +526,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// Byte string patterns behave the same way as array patterns
|
// Byte string patterns behave the same way as array patterns
|
||||||
// They can denote both statically and dynamically-sized byte arrays.
|
// They can denote both statically and dynamically-sized byte arrays.
|
||||||
let mut pat_ty = ty;
|
let mut pat_ty = ty;
|
||||||
if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind {
|
if let hir::PatExprKind::Lit {
|
||||||
|
lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
|
||||||
|
} = lt.kind
|
||||||
|
{
|
||||||
let expected = self.structurally_resolve_type(span, expected);
|
let expected = self.structurally_resolve_type(span, expected);
|
||||||
if let ty::Ref(_, inner_ty, _) = *expected.kind()
|
if let ty::Ref(_, inner_ty, _) = *expected.kind()
|
||||||
&& self.try_structurally_resolve_type(span, inner_ty).is_slice()
|
&& self.try_structurally_resolve_type(span, inner_ty).is_slice()
|
||||||
|
@ -524,7 +546,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tcx.features().string_deref_patterns()
|
if self.tcx.features().string_deref_patterns()
|
||||||
&& let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind
|
&& let hir::PatExprKind::Lit {
|
||||||
|
lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
|
||||||
|
} = lt.kind
|
||||||
{
|
{
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let expected = self.resolve_vars_if_possible(expected);
|
let expected = self.resolve_vars_if_possible(expected);
|
||||||
|
@ -565,15 +589,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn check_pat_range(
|
fn check_pat_range(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
lhs: Option<&'tcx hir::Expr<'tcx>>,
|
lhs: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||||
rhs: Option<&'tcx hir::Expr<'tcx>>,
|
rhs: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
ti: &TopInfo<'tcx>,
|
ti: &TopInfo<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
|
let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
|
||||||
None => None,
|
None => None,
|
||||||
Some(expr) => {
|
Some(expr) => {
|
||||||
let ty = self.check_expr(expr);
|
let ty = self.check_pat_expr_unadjusted(expr);
|
||||||
// Check that the end-point is possibly of numeric or char type.
|
// Check that the end-point is possibly of numeric or char type.
|
||||||
// The early check here is not for correctness, but rather better
|
// The early check here is not for correctness, but rather better
|
||||||
// diagnostics (e.g. when `&str` is being matched, `expected` will
|
// diagnostics (e.g. when `&str` is being matched, `expected` will
|
||||||
|
@ -919,7 +943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
| PatKind::Box(..)
|
| PatKind::Box(..)
|
||||||
| PatKind::Deref(_)
|
| PatKind::Deref(_)
|
||||||
| PatKind::Ref(..)
|
| PatKind::Ref(..)
|
||||||
| PatKind::Lit(..)
|
| PatKind::Expr(..)
|
||||||
| PatKind::Range(..)
|
| PatKind::Range(..)
|
||||||
| PatKind::Err(_) => break 'block None,
|
| PatKind::Err(_) => break 'block None,
|
||||||
},
|
},
|
||||||
|
@ -1053,7 +1077,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
fn check_pat_path(
|
fn check_pat_path(
|
||||||
&self,
|
&self,
|
||||||
pat: &Pat<'tcx>,
|
hir_id: HirId,
|
||||||
|
span: Span,
|
||||||
qpath: &hir::QPath<'_>,
|
qpath: &hir::QPath<'_>,
|
||||||
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
|
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
|
@ -1072,8 +1097,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
|
Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
|
||||||
let expected = "unit struct, unit variant or constant";
|
let expected = "unit struct, unit variant or constant";
|
||||||
let e =
|
let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
|
||||||
report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0533, expected);
|
|
||||||
return Ty::new_error(tcx, e);
|
return Ty::new_error(tcx, e);
|
||||||
}
|
}
|
||||||
Res::SelfCtor(def_id) => {
|
Res::SelfCtor(def_id) => {
|
||||||
|
@ -1088,7 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
res,
|
res,
|
||||||
None,
|
None,
|
||||||
qpath,
|
qpath,
|
||||||
pat.span,
|
span,
|
||||||
E0533,
|
E0533,
|
||||||
"unit struct",
|
"unit struct",
|
||||||
);
|
);
|
||||||
|
@ -1107,11 +1131,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
// Type-check the path.
|
// Type-check the path.
|
||||||
let (pat_ty, pat_res) =
|
let (pat_ty, pat_res) =
|
||||||
self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
|
self.instantiate_value_path(segments, opt_ty, res, span, span, hir_id);
|
||||||
if let Err(err) =
|
if let Err(err) =
|
||||||
self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty)
|
self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty)
|
||||||
{
|
{
|
||||||
self.emit_bad_pat_path(err, pat, res, pat_res, pat_ty, segments);
|
self.emit_bad_pat_path(err, hir_id, span, res, pat_res, pat_ty, segments);
|
||||||
}
|
}
|
||||||
pat_ty
|
pat_ty
|
||||||
}
|
}
|
||||||
|
@ -1154,13 +1178,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn emit_bad_pat_path(
|
fn emit_bad_pat_path(
|
||||||
&self,
|
&self,
|
||||||
mut e: Diag<'_>,
|
mut e: Diag<'_>,
|
||||||
pat: &hir::Pat<'tcx>,
|
hir_id: HirId,
|
||||||
|
pat_span: Span,
|
||||||
res: Res,
|
res: Res,
|
||||||
pat_res: Res,
|
pat_res: Res,
|
||||||
pat_ty: Ty<'tcx>,
|
pat_ty: Ty<'tcx>,
|
||||||
segments: &'tcx [hir::PathSegment<'tcx>],
|
segments: &'tcx [hir::PathSegment<'tcx>],
|
||||||
) {
|
) {
|
||||||
let pat_span = pat.span;
|
|
||||||
if let Some(span) = self.tcx.hir().res_span(pat_res) {
|
if let Some(span) = self.tcx.hir().res_span(pat_res) {
|
||||||
e.span_label(span, format!("{} defined here", res.descr()));
|
e.span_label(span, format!("{} defined here", res.descr()));
|
||||||
if let [hir::PathSegment { ident, .. }] = &*segments {
|
if let [hir::PathSegment { ident, .. }] = &*segments {
|
||||||
|
@ -1173,7 +1197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
res.descr(),
|
res.descr(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
match self.tcx.parent_hir_node(pat.hir_id) {
|
match self.tcx.parent_hir_node(hir_id) {
|
||||||
hir::Node::PatField(..) => {
|
hir::Node::PatField(..) => {
|
||||||
e.span_suggestion_verbose(
|
e.span_suggestion_verbose(
|
||||||
ident.span.shrink_to_hi(),
|
ident.span.shrink_to_hi(),
|
||||||
|
@ -1813,9 +1837,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
} else if inexistent_fields.len() == 1 {
|
} else if inexistent_fields.len() == 1 {
|
||||||
match pat_field.pat.kind {
|
match pat_field.pat.kind {
|
||||||
PatKind::Lit(expr)
|
PatKind::Expr(_)
|
||||||
if !self.may_coerce(
|
if !self.may_coerce(
|
||||||
self.typeck_results.borrow().expr_ty(expr),
|
self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
|
||||||
self.field_ty(field.span, field_def, args),
|
self.field_ty(field.span, field_def, args),
|
||||||
) => {}
|
) => {}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -147,15 +147,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
|
||||||
self.visit_body(body);
|
self.visit_body(body);
|
||||||
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
|
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
|
||||||
}
|
}
|
||||||
hir::ExprKind::ConstBlock(anon_const) => {
|
|
||||||
let body = self.fcx.tcx.hir().body(anon_const.body);
|
|
||||||
self.visit_body(body);
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
intravisit::walk_expr(self, expr);
|
intravisit::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
|
||||||
|
let body = self.fcx.tcx.hir().body(c.body);
|
||||||
|
self.visit_body(body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
|
@ -246,6 +246,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_const_block(&mut self, span: Span, anon_const: &hir::ConstBlock) {
|
||||||
|
self.visit_node_id(span, anon_const.hir_id);
|
||||||
|
|
||||||
|
let body = self.tcx().hir().body(anon_const.body);
|
||||||
|
self.visit_body(body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -275,11 +282,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||||
hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
|
hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
|
||||||
self.visit_field_id(e.hir_id);
|
self.visit_field_id(e.hir_id);
|
||||||
}
|
}
|
||||||
hir::ExprKind::ConstBlock(anon_const) => {
|
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||||
self.visit_node_id(e.span, anon_const.hir_id);
|
self.visit_const_block(e.span, anon_const);
|
||||||
|
|
||||||
let body = self.tcx().hir().body(anon_const.body);
|
|
||||||
self.visit_body(body);
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -335,6 +339,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||||
intravisit::walk_pat(self, p);
|
intravisit::walk_pat(self, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) {
|
||||||
|
self.visit_node_id(expr.span, expr.hir_id);
|
||||||
|
if let hir::PatExprKind::ConstBlock(c) = &expr.kind {
|
||||||
|
self.visit_const_block(expr.span, c);
|
||||||
|
}
|
||||||
|
intravisit::walk_pat_expr(self, expr);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
|
fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
|
||||||
intravisit::walk_local(self, l);
|
intravisit::walk_local(self, l);
|
||||||
let var_ty = self.fcx.local_ty(l.span, l.hir_id);
|
let var_ty = self.fcx.local_ty(l.span, l.hir_id);
|
||||||
|
|
|
@ -1220,7 +1220,7 @@ impl EarlyLintPass for UnusedParens {
|
||||||
// Do not lint on `(..)` as that will result in the other arms being useless.
|
// Do not lint on `(..)` as that will result in the other arms being useless.
|
||||||
Paren(_)
|
Paren(_)
|
||||||
// The other cases do not contain sub-patterns.
|
// The other cases do not contain sub-patterns.
|
||||||
| Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
|
| Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
|
||||||
// These are list-like patterns; parens can always be removed.
|
// These are list-like patterns; parens can always be removed.
|
||||||
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
||||||
self.check_unused_parens_pat(cx, p, false, false, keep_space);
|
self.check_unused_parens_pat(cx, p, false, false, keep_space);
|
||||||
|
|
|
@ -938,6 +938,7 @@ impl<'hir> Map<'hir> {
|
||||||
Node::OpaqueTy(op) => op.span,
|
Node::OpaqueTy(op) => op.span,
|
||||||
Node::Pat(pat) => pat.span,
|
Node::Pat(pat) => pat.span,
|
||||||
Node::PatField(field) => field.span,
|
Node::PatField(field) => field.span,
|
||||||
|
Node::PatExpr(lit) => lit.span,
|
||||||
Node::Arm(arm) => arm.span,
|
Node::Arm(arm) => arm.span,
|
||||||
Node::Block(block) => block.span,
|
Node::Block(block) => block.span,
|
||||||
Node::Ctor(..) => self.span_with_body(self.tcx.parent_hir_id(hir_id)),
|
Node::Ctor(..) => self.span_with_body(self.tcx.parent_hir_id(hir_id)),
|
||||||
|
@ -1209,6 +1210,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
|
||||||
Node::OpaqueTy(_) => node_str("opaque type"),
|
Node::OpaqueTy(_) => node_str("opaque type"),
|
||||||
Node::Pat(_) => node_str("pat"),
|
Node::Pat(_) => node_str("pat"),
|
||||||
Node::PatField(_) => node_str("pattern field"),
|
Node::PatField(_) => node_str("pattern field"),
|
||||||
|
Node::PatExpr(_) => node_str("pattern literal"),
|
||||||
Node::Param(_) => node_str("param"),
|
Node::Param(_) => node_str("param"),
|
||||||
Node::Arm(_) => node_str("arm"),
|
Node::Arm(_) => node_str("arm"),
|
||||||
Node::Block(_) => node_str("block"),
|
Node::Block(_) => node_str("block"),
|
||||||
|
|
|
@ -154,7 +154,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
fn lower_pattern_range_endpoint(
|
fn lower_pattern_range_endpoint(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: Option<&'tcx hir::Expr<'tcx>>,
|
expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
|
(Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
|
||||||
ErrorGuaranteed,
|
ErrorGuaranteed,
|
||||||
|
@ -200,13 +200,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
/// This is only called when the range is already known to be malformed.
|
/// This is only called when the range is already known to be malformed.
|
||||||
fn error_on_literal_overflow(
|
fn error_on_literal_overflow(
|
||||||
&self,
|
&self,
|
||||||
expr: Option<&'tcx hir::Expr<'tcx>>,
|
expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
use hir::{ExprKind, UnOp};
|
|
||||||
use rustc_ast::ast::LitKind;
|
use rustc_ast::ast::LitKind;
|
||||||
|
|
||||||
let Some(mut expr) = expr else {
|
let Some(expr) = expr else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
let span = expr.span;
|
let span = expr.span;
|
||||||
|
@ -214,12 +213,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
// We need to inspect the original expression, because if we only inspect the output of
|
// We need to inspect the original expression, because if we only inspect the output of
|
||||||
// `eval_bits`, an overflowed value has already been wrapped around.
|
// `eval_bits`, an overflowed value has already been wrapped around.
|
||||||
// We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint.
|
// We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint.
|
||||||
let mut negated = false;
|
let hir::PatExprKind::Lit { lit, negated } = expr.kind else {
|
||||||
if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind {
|
|
||||||
negated = true;
|
|
||||||
expr = sub_expr;
|
|
||||||
}
|
|
||||||
let ExprKind::Lit(lit) = expr.kind else {
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
let LitKind::Int(lit_val, _) = lit.node else {
|
let LitKind::Int(lit_val, _) = lit.node else {
|
||||||
|
@ -248,8 +242,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
fn lower_pattern_range(
|
fn lower_pattern_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
lo_expr: Option<&'tcx hir::Expr<'tcx>>,
|
lo_expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||||
hi_expr: Option<&'tcx hir::Expr<'tcx>>,
|
hi_expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||||
end: RangeEnd,
|
end: RangeEnd,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -330,7 +324,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
hir::PatKind::Never => PatKind::Never,
|
hir::PatKind::Never => PatKind::Never,
|
||||||
|
|
||||||
hir::PatKind::Lit(value) => self.lower_lit(value),
|
hir::PatKind::Expr(value) => self.lower_lit(value),
|
||||||
|
|
||||||
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
|
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
|
||||||
let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
|
let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
|
||||||
|
@ -662,25 +656,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
/// The special case for negation exists to allow things like `-128_i8`
|
/// The special case for negation exists to allow things like `-128_i8`
|
||||||
/// which would overflow if we tried to evaluate `128_i8` and then negate
|
/// which would overflow if we tried to evaluate `128_i8` and then negate
|
||||||
/// afterwards.
|
/// afterwards.
|
||||||
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
|
fn lower_lit(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> {
|
||||||
let (lit, neg) = match expr.kind {
|
let (lit, neg) = match &expr.kind {
|
||||||
hir::ExprKind::Path(ref qpath) => {
|
hir::PatExprKind::Path(qpath) => {
|
||||||
return self.lower_path(qpath, expr.hir_id, expr.span).kind;
|
return self.lower_path(qpath, expr.hir_id, expr.span).kind;
|
||||||
}
|
}
|
||||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
hir::PatExprKind::ConstBlock(anon_const) => {
|
||||||
return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
|
return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
|
||||||
}
|
}
|
||||||
hir::ExprKind::Lit(ref lit) => (lit, false),
|
hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
|
||||||
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
|
|
||||||
let hir::ExprKind::Lit(ref lit) = expr.kind else {
|
|
||||||
span_bug!(expr.span, "not a literal: {:?}", expr);
|
|
||||||
};
|
|
||||||
(lit, true)
|
|
||||||
}
|
|
||||||
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let ct_ty = self.typeck_results.expr_ty(expr);
|
let ct_ty = self.typeck_results.node_type(expr.hir_id);
|
||||||
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
|
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
|
||||||
match self.tcx.at(expr.span).lit_to_const(lit_input) {
|
match self.tcx.at(expr.span).lit_to_const(lit_input) {
|
||||||
Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind,
|
Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind,
|
||||||
|
|
|
@ -656,14 +656,14 @@ impl<'a> Parser<'a> {
|
||||||
fn visit_pat(&mut self, p: &'a Pat) -> Self::Result {
|
fn visit_pat(&mut self, p: &'a Pat) -> Self::Result {
|
||||||
match &p.kind {
|
match &p.kind {
|
||||||
// Base expression
|
// Base expression
|
||||||
PatKind::Err(_) | PatKind::Lit(_) => {
|
PatKind::Err(_) | PatKind::Expr(_) => {
|
||||||
self.maybe_add_suggestions_then_emit(p.span, p.span, false)
|
self.maybe_add_suggestions_then_emit(p.span, p.span, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sub-patterns
|
// Sub-patterns
|
||||||
// FIXME: this doesn't work with recursive subpats (`&mut &mut <err>`)
|
// FIXME: this doesn't work with recursive subpats (`&mut &mut <err>`)
|
||||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _)
|
PatKind::Box(subpat) | PatKind::Ref(subpat, _)
|
||||||
if matches!(subpat.kind, PatKind::Err(_) | PatKind::Lit(_)) =>
|
if matches!(subpat.kind, PatKind::Err(_) | PatKind::Expr(_)) =>
|
||||||
{
|
{
|
||||||
self.maybe_add_suggestions_then_emit(subpat.span, p.span, false)
|
self.maybe_add_suggestions_then_emit(subpat.span, p.span, false)
|
||||||
}
|
}
|
||||||
|
@ -766,7 +766,7 @@ impl<'a> Parser<'a> {
|
||||||
if let Some(re) = self.parse_range_end() {
|
if let Some(re) = self.parse_range_end() {
|
||||||
self.parse_pat_range_begin_with(const_expr, re)?
|
self.parse_pat_range_begin_with(const_expr, re)?
|
||||||
} else {
|
} else {
|
||||||
PatKind::Lit(const_expr)
|
PatKind::Expr(const_expr)
|
||||||
}
|
}
|
||||||
} else if self.is_builtin() {
|
} else if self.is_builtin() {
|
||||||
self.parse_pat_builtin()?
|
self.parse_pat_builtin()?
|
||||||
|
@ -833,7 +833,7 @@ impl<'a> Parser<'a> {
|
||||||
.struct_span_err(self_.token.span, msg)
|
.struct_span_err(self_.token.span, msg)
|
||||||
.with_span_label(self_.token.span, format!("expected {expected}"))
|
.with_span_label(self_.token.span, format!("expected {expected}"))
|
||||||
});
|
});
|
||||||
PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
|
PatKind::Expr(self.mk_expr(lo, ExprKind::Lit(lit)))
|
||||||
} else {
|
} else {
|
||||||
// Try to parse everything else as literal with optional minus
|
// Try to parse everything else as literal with optional minus
|
||||||
match self.parse_literal_maybe_minus() {
|
match self.parse_literal_maybe_minus() {
|
||||||
|
@ -845,7 +845,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
match self.parse_range_end() {
|
match self.parse_range_end() {
|
||||||
Some(form) => self.parse_pat_range_begin_with(begin, form)?,
|
Some(form) => self.parse_pat_range_begin_with(begin, form)?,
|
||||||
None => PatKind::Lit(begin),
|
None => PatKind::Expr(begin),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => return self.fatal_unexpected_non_pat(err, expected),
|
Err(err) => return self.fatal_unexpected_non_pat(err, expected),
|
||||||
|
@ -989,7 +989,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
match &pat.kind {
|
match &pat.kind {
|
||||||
// recover ranges with parentheses around the `(start)..`
|
// recover ranges with parentheses around the `(start)..`
|
||||||
PatKind::Lit(begin)
|
PatKind::Expr(begin)
|
||||||
if self.may_recover()
|
if self.may_recover()
|
||||||
&& let Some(form) = self.parse_range_end() =>
|
&& let Some(form) = self.parse_range_end() =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -304,7 +304,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
Box,
|
Box,
|
||||||
Deref,
|
Deref,
|
||||||
Ref,
|
Ref,
|
||||||
Lit,
|
Expr,
|
||||||
Guard,
|
Guard,
|
||||||
Range,
|
Range,
|
||||||
Slice,
|
Slice,
|
||||||
|
@ -587,7 +587,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
Box,
|
Box,
|
||||||
Deref,
|
Deref,
|
||||||
Ref,
|
Ref,
|
||||||
Lit,
|
Expr,
|
||||||
Range,
|
Range,
|
||||||
Slice,
|
Slice,
|
||||||
Rest,
|
Rest,
|
||||||
|
|
|
@ -1130,7 +1130,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
let None = following_seg else { return };
|
let None = following_seg else { return };
|
||||||
for rib in self.ribs[ValueNS].iter().rev() {
|
for rib in self.ribs[ValueNS].iter().rev() {
|
||||||
for (def_id, spans) in &rib.patterns_with_skipped_bindings {
|
for (def_id, spans) in &rib.patterns_with_skipped_bindings {
|
||||||
if let Some(fields) = self.r.field_idents(*def_id) {
|
if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id)
|
||||||
|
&& let Some(fields) = self.r.field_idents(*def_id)
|
||||||
|
{
|
||||||
for field in fields {
|
for field in fields {
|
||||||
if field.name == segment.ident.name {
|
if field.name == segment.ident.name {
|
||||||
if spans.iter().all(|(_, had_error)| had_error.is_err()) {
|
if spans.iter().all(|(_, had_error)| had_error.is_err()) {
|
||||||
|
|
|
@ -1592,15 +1592,9 @@ impl Step for Extended {
|
||||||
prepare("cargo");
|
prepare("cargo");
|
||||||
prepare("rust-std");
|
prepare("rust-std");
|
||||||
prepare("rust-analysis");
|
prepare("rust-analysis");
|
||||||
|
prepare("clippy");
|
||||||
for tool in &[
|
prepare("rust-analyzer");
|
||||||
"clippy",
|
for tool in &["rust-docs", "miri", "rustc-codegen-cranelift"] {
|
||||||
"rustfmt",
|
|
||||||
"rust-analyzer",
|
|
||||||
"rust-docs",
|
|
||||||
"miri",
|
|
||||||
"rustc-codegen-cranelift",
|
|
||||||
] {
|
|
||||||
if built_tools.contains(tool) {
|
if built_tools.contains(tool) {
|
||||||
prepare(tool);
|
prepare(tool);
|
||||||
}
|
}
|
||||||
|
@ -1640,8 +1634,6 @@ impl Step for Extended {
|
||||||
"rust-analyzer-preview".to_string()
|
"rust-analyzer-preview".to_string()
|
||||||
} else if name == "clippy" {
|
} else if name == "clippy" {
|
||||||
"clippy-preview".to_string()
|
"clippy-preview".to_string()
|
||||||
} else if name == "rustfmt" {
|
|
||||||
"rustfmt-preview".to_string()
|
|
||||||
} else if name == "miri" {
|
} else if name == "miri" {
|
||||||
"miri-preview".to_string()
|
"miri-preview".to_string()
|
||||||
} else if name == "rustc-codegen-cranelift" {
|
} else if name == "rustc-codegen-cranelift" {
|
||||||
|
@ -1661,7 +1653,7 @@ impl Step for Extended {
|
||||||
prepare("cargo");
|
prepare("cargo");
|
||||||
prepare("rust-analysis");
|
prepare("rust-analysis");
|
||||||
prepare("rust-std");
|
prepare("rust-std");
|
||||||
for tool in &["clippy", "rustfmt", "rust-analyzer", "rust-docs", "miri"] {
|
for tool in &["clippy", "rust-analyzer", "rust-docs", "miri"] {
|
||||||
if built_tools.contains(tool) {
|
if built_tools.contains(tool) {
|
||||||
prepare(tool);
|
prepare(tool);
|
||||||
}
|
}
|
||||||
|
@ -1779,24 +1771,6 @@ impl Step for Extended {
|
||||||
.arg(etc.join("msi/remove-duplicates.xsl"))
|
.arg(etc.join("msi/remove-duplicates.xsl"))
|
||||||
.run(builder);
|
.run(builder);
|
||||||
}
|
}
|
||||||
if built_tools.contains("rustfmt") {
|
|
||||||
command(&heat)
|
|
||||||
.current_dir(&exe)
|
|
||||||
.arg("dir")
|
|
||||||
.arg("rustfmt")
|
|
||||||
.args(heat_flags)
|
|
||||||
.arg("-cg")
|
|
||||||
.arg("RustFmtGroup")
|
|
||||||
.arg("-dr")
|
|
||||||
.arg("RustFmt")
|
|
||||||
.arg("-var")
|
|
||||||
.arg("var.RustFmtDir")
|
|
||||||
.arg("-out")
|
|
||||||
.arg(exe.join("RustFmtGroup.wxs"))
|
|
||||||
.arg("-t")
|
|
||||||
.arg(etc.join("msi/remove-duplicates.xsl"))
|
|
||||||
.run(builder);
|
|
||||||
}
|
|
||||||
if built_tools.contains("miri") {
|
if built_tools.contains("miri") {
|
||||||
command(&heat)
|
command(&heat)
|
||||||
.current_dir(&exe)
|
.current_dir(&exe)
|
||||||
|
@ -1868,9 +1842,6 @@ impl Step for Extended {
|
||||||
if built_tools.contains("clippy") {
|
if built_tools.contains("clippy") {
|
||||||
cmd.arg("-dClippyDir=clippy");
|
cmd.arg("-dClippyDir=clippy");
|
||||||
}
|
}
|
||||||
if built_tools.contains("rustfmt") {
|
|
||||||
cmd.arg("-dRustFmtDir=rustfmt");
|
|
||||||
}
|
|
||||||
if built_tools.contains("rust-docs") {
|
if built_tools.contains("rust-docs") {
|
||||||
cmd.arg("-dDocsDir=rust-docs");
|
cmd.arg("-dDocsDir=rust-docs");
|
||||||
}
|
}
|
||||||
|
@ -1897,9 +1868,6 @@ impl Step for Extended {
|
||||||
if built_tools.contains("clippy") {
|
if built_tools.contains("clippy") {
|
||||||
candle("ClippyGroup.wxs".as_ref());
|
candle("ClippyGroup.wxs".as_ref());
|
||||||
}
|
}
|
||||||
if built_tools.contains("rustfmt") {
|
|
||||||
candle("RustFmtGroup.wxs".as_ref());
|
|
||||||
}
|
|
||||||
if built_tools.contains("miri") {
|
if built_tools.contains("miri") {
|
||||||
candle("MiriGroup.wxs".as_ref());
|
candle("MiriGroup.wxs".as_ref());
|
||||||
}
|
}
|
||||||
|
@ -1938,9 +1906,6 @@ impl Step for Extended {
|
||||||
if built_tools.contains("clippy") {
|
if built_tools.contains("clippy") {
|
||||||
cmd.arg("ClippyGroup.wixobj");
|
cmd.arg("ClippyGroup.wixobj");
|
||||||
}
|
}
|
||||||
if built_tools.contains("rustfmt") {
|
|
||||||
cmd.arg("RustFmtGroup.wixobj");
|
|
||||||
}
|
|
||||||
if built_tools.contains("miri") {
|
if built_tools.contains("miri") {
|
||||||
cmd.arg("MiriGroup.wixobj");
|
cmd.arg("MiriGroup.wixobj");
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,11 +172,6 @@
|
||||||
<!-- tool-rust-docs-end -->
|
<!-- tool-rust-docs-end -->
|
||||||
<Directory Id="Cargo" Name="." />
|
<Directory Id="Cargo" Name="." />
|
||||||
<Directory Id="Std" Name="." />
|
<Directory Id="Std" Name="." />
|
||||||
<Directory Id="RustFmt" Name="." />
|
|
||||||
<Directory Id="RustAnalyzer" Name="." />
|
|
||||||
<Directory Id="Miri" Name="." />
|
|
||||||
<Directory Id="Analysis" Name="." />
|
|
||||||
<Directory Id="Clippy" Name="." />
|
|
||||||
</Directory>
|
</Directory>
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
|
@ -284,41 +279,7 @@
|
||||||
<ComponentRef Id="PathEnvPerMachine" />
|
<ComponentRef Id="PathEnvPerMachine" />
|
||||||
<ComponentRef Id="PathEnvPerUser" />
|
<ComponentRef Id="PathEnvPerUser" />
|
||||||
</Feature>
|
</Feature>
|
||||||
<Feature Id="RustFmt"
|
|
||||||
Title="Formatter for rust"
|
|
||||||
Display="7"
|
|
||||||
Level="1"
|
|
||||||
AllowAdvertise="no">
|
|
||||||
<ComponentGroupRef Id="RustFmtGroup" />
|
|
||||||
</Feature>
|
|
||||||
<Feature Id="Clippy"
|
|
||||||
Title="Formatter and checker for rust"
|
|
||||||
Display="8"
|
|
||||||
Level="1"
|
|
||||||
AllowAdvertise="no">
|
|
||||||
<ComponentGroupRef Id="ClippyGroup" />
|
|
||||||
</Feature>
|
|
||||||
<Feature Id="Miri"
|
|
||||||
Title="Soundness checker for rust"
|
|
||||||
Display="9"
|
|
||||||
Level="1"
|
|
||||||
AllowAdvertise="no">
|
|
||||||
<ComponentGroupRef Id="MiriGroup" />
|
|
||||||
</Feature>
|
|
||||||
<Feature Id="RustAnalyzer"
|
|
||||||
Title="Analyzer for rust"
|
|
||||||
Display="10"
|
|
||||||
Level="1"
|
|
||||||
AllowAdvertise="no">
|
|
||||||
<ComponentGroupRef Id="RustAnalyzerGroup" />
|
|
||||||
</Feature>
|
|
||||||
<Feature Id="Analysis"
|
|
||||||
Title="Analysis for rust"
|
|
||||||
Display="11"
|
|
||||||
Level="1"
|
|
||||||
AllowAdvertise="no">
|
|
||||||
<ComponentGroupRef Id="AnalysisGroup" />
|
|
||||||
</Feature>
|
|
||||||
<UIRef Id="RustUI" />
|
<UIRef Id="RustUI" />
|
||||||
</Product>
|
</Product>
|
||||||
</Wix>
|
</Wix>
|
||||||
|
|
|
@ -314,9 +314,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
|
||||||
PatKind::Box(p) => return name_from_pat(p),
|
PatKind::Box(p) => return name_from_pat(p),
|
||||||
PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)),
|
PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)),
|
||||||
PatKind::Ref(p, _) => return name_from_pat(p),
|
PatKind::Ref(p, _) => return name_from_pat(p),
|
||||||
PatKind::Lit(..) => {
|
PatKind::Expr(..) => {
|
||||||
warn!(
|
warn!(
|
||||||
"tried to get argument name from PatKind::Lit, which is silly in function arguments"
|
"tried to get argument name from PatKind::Expr, which is silly in function arguments"
|
||||||
);
|
);
|
||||||
return Symbol::intern("()");
|
return Symbol::intern("()");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,11 @@ use clippy_utils::numeric_literal;
|
||||||
use clippy_utils::source::snippet_opt;
|
use clippy_utils::source::snippet_opt;
|
||||||
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
|
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt};
|
use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat, walk_stmt};
|
||||||
use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind, StructTailExpr};
|
use rustc_hir::{
|
||||||
|
Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Pat, PatExpr, PatExprKind, PatKind, Stmt, StmtKind,
|
||||||
|
StructTailExpr,
|
||||||
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
|
use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
|
||||||
|
@ -219,6 +222,22 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
|
||||||
walk_expr(self, expr);
|
walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
|
||||||
|
match pat.kind {
|
||||||
|
PatKind::Expr(&PatExpr {
|
||||||
|
hir_id,
|
||||||
|
kind: PatExprKind::Lit { lit, .. },
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let ty = self.cx.typeck_results().node_type(hir_id);
|
||||||
|
self.check_lit(lit, ty, hir_id);
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
walk_pat(self, pat)
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
|
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
// we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`
|
// we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`
|
||||||
|
|
|
@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
|
||||||
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
|
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
|
||||||
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
|
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
|
||||||
PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
|
PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
|
||||||
PatKind::Path(_) | PatKind::Lit(_) => true,
|
PatKind::Path(_) | PatKind::Expr(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ use rustc_hir::def::Res;
|
||||||
use rustc_hir::def_id::{DefId, DefIdSet};
|
use rustc_hir::def_id::{DefId, DefIdSet};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
|
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
|
||||||
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath,
|
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy,
|
||||||
TraitItemRef, TyKind,
|
QPath, TraitItemRef, TyKind,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
||||||
|
@ -163,7 +163,13 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
|
||||||
if let ExprKind::Let(lt) = expr.kind
|
if let ExprKind::Let(lt) = expr.kind
|
||||||
&& match lt.pat.kind {
|
&& match lt.pat.kind {
|
||||||
PatKind::Slice([], None, []) => true,
|
PatKind::Slice([], None, []) => true,
|
||||||
PatKind::Lit(lit) if is_empty_string(lit) => true,
|
PatKind::Expr(lit) => match lit.kind {
|
||||||
|
PatExprKind::Lit { lit, .. } => match lit.node {
|
||||||
|
LitKind::Str(lit, _) => lit.as_str().is_empty(),
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
&& !expr.span.from_expansion()
|
&& !expr.span.from_expansion()
|
||||||
|
|
|
@ -7,7 +7,7 @@ use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operator
|
||||||
use rustc_ast::LitKind::{Byte, Char};
|
use rustc_ast::LitKind::{Byte, Char};
|
||||||
use rustc_ast::ast::RangeLimits;
|
use rustc_ast::ast::RangeLimits;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd};
|
use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd, PatExpr, PatExprKind, Lit};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_session::impl_lint_pass;
|
use rustc_session::impl_lint_pass;
|
||||||
|
@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
||||||
{
|
{
|
||||||
let arg = peel_ref_operators(cx, arg);
|
let arg = peel_ref_operators(cx, arg);
|
||||||
let ty_sugg = get_ty_sugg(cx, arg, start);
|
let ty_sugg = get_ty_sugg(cx, arg, start);
|
||||||
let range = check_range(start, end);
|
let range = check_expr_range(start, end);
|
||||||
check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
|
check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,10 +196,28 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
|
fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
|
||||||
if let ExprKind::Lit(start_lit) = &start.kind
|
if let ExprKind::Lit(start_lit) = &start.kind
|
||||||
&& let ExprKind::Lit(end_lit) = &end.kind
|
&& let ExprKind::Lit(end_lit) = &end.kind
|
||||||
{
|
{
|
||||||
|
check_lit_range(start_lit, end_lit)
|
||||||
|
} else {
|
||||||
|
CharRange::Otherwise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn check_range(start: &PatExpr<'_>, end: &PatExpr<'_>) -> CharRange {
|
||||||
|
if let PatExprKind::Lit{ lit: start_lit, negated: false } = &start.kind
|
||||||
|
&& let PatExprKind::Lit{ lit: end_lit, negated: false } = &end.kind
|
||||||
|
{
|
||||||
|
check_lit_range(start_lit, end_lit)
|
||||||
|
} else {
|
||||||
|
CharRange::Otherwise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_lit_range(start_lit: &Lit, end_lit: &Lit) -> CharRange {
|
||||||
match (&start_lit.node, &end_lit.node) {
|
match (&start_lit.node, &end_lit.node) {
|
||||||
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
|
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
|
||||||
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
|
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
|
||||||
|
@ -208,7 +226,4 @@ fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
|
||||||
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
|
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
|
||||||
_ => CharRange::Otherwise,
|
_ => CharRange::Otherwise,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
CharRange::Otherwise
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt;
|
||||||
use rustc_ast::LitKind;
|
use rustc_ast::LitKind;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp};
|
use rustc_hir::{PatExpr, PatExprKind, PatKind, RangeEnd};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
@ -38,14 +38,13 @@ declare_clippy_lint! {
|
||||||
}
|
}
|
||||||
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
|
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
|
||||||
|
|
||||||
fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> {
|
fn expr_as_i128(expr: &PatExpr<'_>) -> Option<i128> {
|
||||||
if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind {
|
if let PatExprKind::Lit { lit, negated } = expr.kind
|
||||||
expr_as_i128(expr).map(|num| -num)
|
|
||||||
} else if let ExprKind::Lit(lit) = expr.kind
|
|
||||||
&& let LitKind::Int(num, _) = lit.node
|
&& let LitKind::Int(num, _) = lit.node
|
||||||
{
|
{
|
||||||
// Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now.
|
// Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now.
|
||||||
num.get().try_into().ok()
|
let n = i128::try_from(num.get()).ok()?;
|
||||||
|
Some(if negated { -n } else { n })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -58,7 +57,7 @@ struct Num {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Num {
|
impl Num {
|
||||||
fn new(expr: &Expr<'_>) -> Option<Self> {
|
fn new(expr: &PatExpr<'_>) -> Option<Self> {
|
||||||
Some(Self {
|
Some(Self {
|
||||||
val: expr_as_i128(expr)?,
|
val: expr_as_i128(expr)?,
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
|
@ -90,7 +89,7 @@ impl LateLintPass<'_> for ManualRangePatterns {
|
||||||
let mut ranges_found = Vec::new();
|
let mut ranges_found = Vec::new();
|
||||||
|
|
||||||
for pat in pats {
|
for pat in pats {
|
||||||
if let PatKind::Lit(lit) = pat.kind
|
if let PatKind::Expr(lit) = pat.kind
|
||||||
&& let Some(num) = Num::new(lit)
|
&& let Some(num) = Num::new(lit)
|
||||||
{
|
{
|
||||||
numbers_found.insert(num.val);
|
numbers_found.insert(num.val);
|
||||||
|
|
|
@ -4,7 +4,7 @@ use clippy_utils::source::{expr_block, snippet};
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
use rustc_ast::LitKind;
|
use rustc_ast::LitKind;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, PatKind};
|
use rustc_hir::{Arm, Expr, PatExprKind, PatKind};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
|
||||||
move |diag| {
|
move |diag| {
|
||||||
if arms.len() == 2 {
|
if arms.len() == 2 {
|
||||||
// no guards
|
// no guards
|
||||||
let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
|
let exprs = if let PatKind::Expr(arm_bool) = arms[0].pat.kind {
|
||||||
if let ExprKind::Lit(lit) = arm_bool.kind {
|
if let PatExprKind::Lit { lit, .. } = arm_bool.kind {
|
||||||
match lit.node {
|
match lit.node {
|
||||||
LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
|
LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
|
||||||
LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
|
LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
|
||||||
use rustc_ast::ast::LitKind;
|
use rustc_ast::ast::LitKind;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd};
|
use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExprKind, PatKind, RangeEnd};
|
||||||
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||||
use rustc_lint::{LateContext, LintContext};
|
use rustc_lint::{LateContext, LintContext};
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
|
@ -311,9 +311,9 @@ impl<'a> NormalizedPat<'a> {
|
||||||
);
|
);
|
||||||
Self::Tuple(None, pats)
|
Self::Tuple(None, pats)
|
||||||
},
|
},
|
||||||
PatKind::Lit(e) => match &e.kind {
|
PatKind::Expr(e) => match &e.kind {
|
||||||
// TODO: Handle negative integers. They're currently treated as a wild match.
|
// TODO: Handle negative integers. They're currently treated as a wild match.
|
||||||
ExprKind::Lit(lit) => match lit.node {
|
PatExprKind::Lit { lit, negated: false } => match lit.node {
|
||||||
LitKind::Str(sym, _) => Self::LitStr(sym),
|
LitKind::Str(sym, _) => Self::LitStr(sym),
|
||||||
LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
|
LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
|
||||||
LitKind::Byte(val) => Self::LitInt(val.into()),
|
LitKind::Byte(val) => Self::LitInt(val.into()),
|
||||||
|
@ -330,7 +330,7 @@ impl<'a> NormalizedPat<'a> {
|
||||||
let start = match start {
|
let start = match start {
|
||||||
None => 0,
|
None => 0,
|
||||||
Some(e) => match &e.kind {
|
Some(e) => match &e.kind {
|
||||||
ExprKind::Lit(lit) => match lit.node {
|
PatExprKind::Lit { lit, negated: false } => match lit.node {
|
||||||
LitKind::Int(val, _) => val.get(),
|
LitKind::Int(val, _) => val.get(),
|
||||||
LitKind::Char(val) => val.into(),
|
LitKind::Char(val) => val.into(),
|
||||||
LitKind::Byte(val) => val.into(),
|
LitKind::Byte(val) => val.into(),
|
||||||
|
@ -342,7 +342,7 @@ impl<'a> NormalizedPat<'a> {
|
||||||
let (end, bounds) = match end {
|
let (end, bounds) = match end {
|
||||||
None => (u128::MAX, RangeEnd::Included),
|
None => (u128::MAX, RangeEnd::Included),
|
||||||
Some(e) => match &e.kind {
|
Some(e) => match &e.kind {
|
||||||
ExprKind::Lit(lit) => match lit.node {
|
PatExprKind::Lit { lit, negated: false } => match lit.node {
|
||||||
LitKind::Int(val, _) => (val.get(), bounds),
|
LitKind::Int(val, _) => (val.get(), bounds),
|
||||||
LitKind::Char(val) => (val.into(), bounds),
|
LitKind::Char(val) => (val.into(), bounds),
|
||||||
LitKind::Byte(val) => (val.into(), bounds),
|
LitKind::Byte(val) => (val.into(), bounds),
|
||||||
|
|
|
@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_lang_item;
|
||||||
use rustc_ast::ast::LitKind;
|
use rustc_ast::ast::LitKind;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::intravisit::{Visitor, walk_expr};
|
use rustc_hir::intravisit::{Visitor, walk_expr};
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind};
|
use rustc_hir::{Arm, Expr, ExprKind, PatExpr, PatExprKind, LangItem, PatKind};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -85,8 +85,8 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
|
||||||
};
|
};
|
||||||
|
|
||||||
for arm in arms {
|
for arm in arms {
|
||||||
if let PatKind::Lit(Expr {
|
if let PatKind::Expr(PatExpr {
|
||||||
kind: ExprKind::Lit(lit),
|
kind: PatExprKind::Lit { lit, negated: false },
|
||||||
..
|
..
|
||||||
}) = arm.pat.kind
|
}) = arm.pat.kind
|
||||||
&& let LitKind::Str(symbol, _) = lit.node
|
&& let LitKind::Str(symbol, _) = lit.node
|
||||||
|
|
|
@ -8,7 +8,7 @@ use clippy_utils::{
|
||||||
};
|
};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::LangItem::OptionNone;
|
use rustc_hir::LangItem::OptionNone;
|
||||||
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatKind, Path, QPath};
|
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
|
||||||
},
|
},
|
||||||
// compare match_expr ty with RetTy in `fn foo() -> RetTy`
|
// compare match_expr ty with RetTy in `fn foo() -> RetTy`
|
||||||
Node::Item(item) => {
|
Node::Item(item) => {
|
||||||
if let ItemKind::Fn{ .. } = item.kind {
|
if let ItemKind::Fn { .. } = item.kind {
|
||||||
let output = cx
|
let output = cx
|
||||||
.tcx
|
.tcx
|
||||||
.fn_sig(item.owner_id)
|
.fn_sig(item.owner_id)
|
||||||
|
@ -189,8 +189,12 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// Example: `5 => 5`
|
// Example: `5 => 5`
|
||||||
(PatKind::Lit(pat_lit_expr), ExprKind::Lit(expr_spanned)) => {
|
(PatKind::Expr(pat_expr_expr), ExprKind::Lit(expr_spanned)) => {
|
||||||
if let ExprKind::Lit(pat_spanned) = &pat_lit_expr.kind {
|
if let PatExprKind::Lit {
|
||||||
|
lit: pat_spanned,
|
||||||
|
negated: false,
|
||||||
|
} = &pat_expr_expr.kind
|
||||||
|
{
|
||||||
return pat_spanned.node == expr_spanned.node;
|
return pat_spanned.node == expr_spanned.node;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,13 +34,13 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||||
if let Arm { pat, guard: None, .. } = *arm {
|
if let Arm { pat, guard: None, .. } = *arm {
|
||||||
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
|
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
|
||||||
let lhs_const = if let Some(lhs) = lhs {
|
let lhs_const = if let Some(lhs) = lhs {
|
||||||
ConstEvalCtxt::new(cx).eval(lhs)?
|
ConstEvalCtxt::new(cx).eval_pat_expr(lhs)?
|
||||||
} else {
|
} else {
|
||||||
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
||||||
mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
|
mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
|
||||||
};
|
};
|
||||||
let rhs_const = if let Some(rhs) = rhs {
|
let rhs_const = if let Some(rhs) = rhs {
|
||||||
ConstEvalCtxt::new(cx).eval(rhs)?
|
ConstEvalCtxt::new(cx).eval_pat_expr(rhs)?
|
||||||
} else {
|
} else {
|
||||||
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
||||||
mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
|
mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
|
||||||
|
@ -57,8 +57,10 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let PatKind::Lit(value) = pat.kind {
|
if let PatKind::Expr(value) = pat.kind {
|
||||||
let value = ConstEvalCtxt::new(cx).eval_full_int(value)?;
|
let value = ConstEvalCtxt::new(cx)
|
||||||
|
.eval_pat_expr(value)?
|
||||||
|
.int_value(cx.tcx, cx.typeck_results().node_type(pat.hir_id))?;
|
||||||
return Some(SpannedRange {
|
return Some(SpannedRange {
|
||||||
span: pat.span,
|
span: pat.span,
|
||||||
node: (value, EndBound::Included(value)),
|
node: (value, EndBound::Included(value)),
|
||||||
|
|
|
@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
|
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
|
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExprKind, PatKind, QPath, UnOp};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty::{self, GenericArgKind, Ty};
|
use rustc_middle::ty::{self, GenericArgKind, Ty};
|
||||||
use rustc_span::{Span, Symbol, sym};
|
use rustc_span::{Span, Symbol, sym};
|
||||||
|
@ -74,8 +74,8 @@ fn find_match_true<'tcx>(
|
||||||
span: Span,
|
span: Span,
|
||||||
message: &'static str,
|
message: &'static str,
|
||||||
) {
|
) {
|
||||||
if let PatKind::Lit(lit) = pat.kind
|
if let PatKind::Expr(lit) = pat.kind
|
||||||
&& let ExprKind::Lit(lit) = lit.kind
|
&& let PatExprKind::Lit { lit, negated: false } = lit.kind
|
||||||
&& let LitKind::Bool(pat_is_true) = lit.node
|
&& let LitKind::Bool(pat_is_true) = lit.node
|
||||||
{
|
{
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use rustc_arena::DroplessArena;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::intravisit::{Visitor, walk_pat};
|
use rustc_hir::intravisit::{Visitor, walk_pat};
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind};
|
use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, StmtKind};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef};
|
use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef};
|
||||||
use rustc_span::{Span, sym};
|
use rustc_span::{Span, sym};
|
||||||
|
@ -114,7 +114,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
|
||||||
}
|
}
|
||||||
|
|
||||||
let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
|
let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
|
||||||
let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind
|
let (msg, sugg) = if let PatKind::Path(_) | PatKind::Expr(_) = pat.kind
|
||||||
&& let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
|
&& let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
|
||||||
&& let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
|
&& let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
|
||||||
&& let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
|
&& let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
|
||||||
|
@ -126,8 +126,8 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
|
||||||
// scrutinee derives PartialEq and the pattern is a constant.
|
// scrutinee derives PartialEq and the pattern is a constant.
|
||||||
let pat_ref_count = match pat.kind {
|
let pat_ref_count = match pat.kind {
|
||||||
// string literals are already a reference.
|
// string literals are already a reference.
|
||||||
PatKind::Lit(Expr {
|
PatKind::Expr(PatExpr {
|
||||||
kind: ExprKind::Lit(lit),
|
kind: PatExprKind::Lit { lit, negated: false },
|
||||||
..
|
..
|
||||||
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
|
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
|
||||||
_ => pat_ref_count,
|
_ => pat_ref_count,
|
||||||
|
@ -384,7 +384,7 @@ impl<'a> PatState<'a> {
|
||||||
|
|
||||||
PatKind::Wild
|
PatKind::Wild
|
||||||
| PatKind::Binding(_, _, _, None)
|
| PatKind::Binding(_, _, _, None)
|
||||||
| PatKind::Lit(_)
|
| PatKind::Expr(_)
|
||||||
| PatKind::Range(..)
|
| PatKind::Range(..)
|
||||||
| PatKind::Path(_)
|
| PatKind::Path(_)
|
||||||
| PatKind::Never
|
| PatKind::Never
|
||||||
|
|
|
@ -11,7 +11,7 @@ use clippy_utils::visitors::{Descend, for_each_expr};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_ast::{BinOpKind, LitKind};
|
use rustc_ast::{BinOpKind, LitKind};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind, PatKind};
|
use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_session::impl_lint_pass;
|
use rustc_session::impl_lint_pass;
|
||||||
|
@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
|
||||||
return ControlFlow::Break(());
|
return ControlFlow::Break(());
|
||||||
}
|
}
|
||||||
if arm.pat.walk_short(|pat| match pat.kind {
|
if arm.pat.walk_short(|pat| match pat.kind {
|
||||||
PatKind::Lit(expr) if let ExprKind::Lit(lit) = expr.kind => {
|
PatKind::Expr(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => {
|
||||||
if let LitKind::Char(_) = lit.node {
|
if let LitKind::Char(_) = lit.node {
|
||||||
set_char_spans.push(lit.span);
|
set_char_spans.push(lit.span);
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ impl EarlyLintPass for UnnestedOrPatterns {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
|
fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
|
||||||
if let Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind {
|
if let Ident(.., None) | Expr(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind {
|
||||||
// This is a leaf pattern, so cloning is unprofitable.
|
// This is a leaf pattern, so cloning is unprofitable.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|
||||||
// Therefore they are not some form of constructor `C`,
|
// Therefore they are not some form of constructor `C`,
|
||||||
// with which a pattern `C(p_0)` may be formed,
|
// with which a pattern `C(p_0)` may be formed,
|
||||||
// which we would want to join with other `C(p_j)`s.
|
// which we would want to join with other `C(p_j)`s.
|
||||||
Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_)
|
Ident(.., None) | Expr(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_)
|
||||||
// Skip immutable refs, as grouping them saves few characters,
|
// Skip immutable refs, as grouping them saves few characters,
|
||||||
// and almost always requires adding parens (increasing noisiness).
|
// and almost always requires adding parens (increasing noisiness).
|
||||||
// In the case of only two patterns, replacement adds net characters.
|
// In the case of only two patterns, replacement adds net characters.
|
||||||
|
|
|
@ -4,7 +4,7 @@ use rustc_ast::ast::{LitFloatType, LitKind};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind,
|
self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind,
|
||||||
FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, StructTailExpr, TyKind,
|
FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, TyKind,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
@ -643,6 +643,27 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||||
self.expr(expr);
|
self.expr(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pat_expr(&self, lit: &Binding<&hir::PatExpr<'_>>) {
|
||||||
|
let kind = |kind| chain!(self, "let PatExprKind::{kind} = {lit}.kind");
|
||||||
|
macro_rules! kind {
|
||||||
|
($($t:tt)*) => (kind(format_args!($($t)*)));
|
||||||
|
}
|
||||||
|
match lit.value.kind {
|
||||||
|
PatExprKind::Lit { lit, negated } => {
|
||||||
|
bind!(self, lit);
|
||||||
|
bind!(self, negated);
|
||||||
|
kind!("Lit{{ref {lit}, {negated} }}");
|
||||||
|
self.lit(lit);
|
||||||
|
},
|
||||||
|
PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"),
|
||||||
|
PatExprKind::Path(ref qpath) => {
|
||||||
|
bind!(self, qpath);
|
||||||
|
kind!("Path(ref {qpath})");
|
||||||
|
self.qpath(qpath);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn pat(&self, pat: &Binding<&hir::Pat<'_>>) {
|
fn pat(&self, pat: &Binding<&hir::Pat<'_>>) {
|
||||||
let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind");
|
let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind");
|
||||||
macro_rules! kind {
|
macro_rules! kind {
|
||||||
|
@ -717,17 +738,17 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||||
kind!("Guard({pat}, {cond})");
|
kind!("Guard({pat}, {cond})");
|
||||||
self.pat(pat);
|
self.pat(pat);
|
||||||
self.expr(cond);
|
self.expr(cond);
|
||||||
}
|
},
|
||||||
PatKind::Lit(lit_expr) => {
|
PatKind::Expr(lit_expr) => {
|
||||||
bind!(self, lit_expr);
|
bind!(self, lit_expr);
|
||||||
kind!("Lit({lit_expr})");
|
kind!("Expr({lit_expr})");
|
||||||
self.expr(lit_expr);
|
self.pat_expr(lit_expr);
|
||||||
},
|
},
|
||||||
PatKind::Range(start, end, end_kind) => {
|
PatKind::Range(start, end, end_kind) => {
|
||||||
opt_bind!(self, start, end);
|
opt_bind!(self, start, end);
|
||||||
kind!("Range({start}, {end}, RangeEnd::{end_kind:?})");
|
kind!("Range({start}, {end}, RangeEnd::{end_kind:?})");
|
||||||
start.if_some(|e| self.expr(e));
|
start.if_some(|e| self.pat_expr(e));
|
||||||
end.if_some(|e| self.expr(e));
|
end.if_some(|e| self.pat_expr(e));
|
||||||
},
|
},
|
||||||
PatKind::Slice(start, middle, end) => {
|
PatKind::Slice(start, middle, end) => {
|
||||||
bind!(self, start, end);
|
bind!(self, start, end);
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
|
||||||
(Paren(l), _) => eq_pat(l, r),
|
(Paren(l), _) => eq_pat(l, r),
|
||||||
(_, Paren(r)) => eq_pat(l, r),
|
(_, Paren(r)) => eq_pat(l, r),
|
||||||
(Wild, Wild) | (Rest, Rest) => true,
|
(Wild, Wild) | (Rest, Rest) => true,
|
||||||
(Lit(l), Lit(r)) => eq_expr(l, r),
|
(Expr(l), Expr(r)) => eq_expr(l, r),
|
||||||
(Ident(b1, i1, s1), Ident(b2, i2, s2)) => {
|
(Ident(b1, i1, s1), Ident(b2, i2, s2)) => {
|
||||||
b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat)
|
b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat)
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
//! executable MIR bodies, so we have to do this instead.
|
//! executable MIR bodies, so we have to do this instead.
|
||||||
#![allow(clippy::float_cmp)]
|
#![allow(clippy::float_cmp)]
|
||||||
|
|
||||||
use crate::macros::HirNode;
|
|
||||||
use crate::source::{SpanRangeExt, walk_span_to_context};
|
use crate::source::{SpanRangeExt, walk_span_to_context};
|
||||||
use crate::{clip, is_direct_expn_of, sext, unsext};
|
use crate::{clip, is_direct_expn_of, sext, unsext};
|
||||||
|
|
||||||
|
@ -13,7 +12,7 @@ use rustc_apfloat::ieee::{Half, Quad};
|
||||||
use rustc_ast::ast::{self, LitFloatType, LitKind};
|
use rustc_ast::ast::{self, LitFloatType, LitKind};
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
|
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp, PatExpr, PatExprKind};
|
||||||
use rustc_lexer::tokenize;
|
use rustc_lexer::tokenize;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::mir::ConstValue;
|
use rustc_middle::mir::ConstValue;
|
||||||
|
@ -442,18 +441,29 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simple constant folding: Insert an expression, get a constant or none.
|
pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option<Constant<'tcx>> {
|
||||||
fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
match &pat_expr.kind {
|
||||||
match e.kind {
|
PatExprKind::Lit { lit, negated } => {
|
||||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
|
let ty = self.typeck.node_type_opt(pat_expr.hir_id);
|
||||||
ExprKind::DropTemps(e) => self.expr(e),
|
let val = lit_to_mir_constant(&lit.node, ty);
|
||||||
ExprKind::Path(ref qpath) => {
|
if *negated {
|
||||||
let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() {
|
self.constant_negate(&val, ty?)
|
||||||
|
} else {
|
||||||
|
Some(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PatExprKind::ConstBlock(ConstBlock { body, ..}) => self.expr(self.tcx.hir().body(*body).value),
|
||||||
|
PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn qpath(&self, qpath: &QPath<'_>, hir_id: HirId) -> Option<Constant<'tcx>> {
|
||||||
|
let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, hir_id).opt_def_id() {
|
||||||
self.tcx.crate_name(def_id.krate) == sym::core
|
self.tcx.crate_name(def_id.krate) == sym::core
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
|
self.fetch_path_and_apply(qpath, hir_id, self.typeck.node_type(hir_id), |self_, result| {
|
||||||
let result = mir_to_const(self_.tcx, result)?;
|
let result = mir_to_const(self_.tcx, result)?;
|
||||||
// If source is already Constant we wouldn't want to override it with CoreConstant
|
// If source is already Constant we wouldn't want to override it with CoreConstant
|
||||||
self_.source.set(
|
self_.source.set(
|
||||||
|
@ -465,7 +475,14 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
|
||||||
);
|
);
|
||||||
Some(result)
|
Some(result)
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
|
|
||||||
|
/// Simple constant folding: Insert an expression, get a constant or none.
|
||||||
|
fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||||
|
match e.kind {
|
||||||
|
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
|
||||||
|
ExprKind::DropTemps(e) => self.expr(e),
|
||||||
|
ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id),
|
||||||
ExprKind::Block(block, _) => self.block(block),
|
ExprKind::Block(block, _) => self.block(block),
|
||||||
ExprKind::Lit(lit) => {
|
ExprKind::Lit(lit) => {
|
||||||
if is_direct_expn_of(e.span, "cfg").is_some() {
|
if is_direct_expn_of(e.span, "cfg").is_some() {
|
||||||
|
|
|
@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
|
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
|
||||||
ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
|
ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
|
||||||
Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty,
|
Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
|
||||||
TyKind,
|
TraitBoundModifiers, Ty, TyKind,
|
||||||
};
|
};
|
||||||
use rustc_lexer::{TokenKind, tokenize};
|
use rustc_lexer::{TokenKind, tokenize};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
|
@ -489,6 +489,24 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||||
li.name == ri.name && self.eq_pat(lp, rp)
|
li.name == ri.name && self.eq_pat(lp, rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool {
|
||||||
|
match (&left.kind, &right.kind) {
|
||||||
|
(
|
||||||
|
&PatExprKind::Lit {
|
||||||
|
lit: left,
|
||||||
|
negated: left_neg,
|
||||||
|
},
|
||||||
|
&PatExprKind::Lit {
|
||||||
|
lit: right,
|
||||||
|
negated: right_neg,
|
||||||
|
},
|
||||||
|
) => left_neg == right_neg && left.node == right.node,
|
||||||
|
(PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body),
|
||||||
|
(PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right),
|
||||||
|
(PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks whether two patterns are the same.
|
/// Checks whether two patterns are the same.
|
||||||
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
|
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
|
||||||
match (&left.kind, &right.kind) {
|
match (&left.kind, &right.kind) {
|
||||||
|
@ -507,11 +525,11 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||||
eq
|
eq
|
||||||
},
|
},
|
||||||
(PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
|
(PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
|
||||||
(&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
|
(&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r),
|
||||||
(&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
|
(&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
|
||||||
(&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
|
(&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
|
||||||
both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_expr(a, b))
|
both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_pat_expr(a, b))
|
||||||
&& both(le.as_ref(), re.as_ref(), |a, b| self.eq_expr(a, b))
|
&& both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b))
|
||||||
&& (li == ri)
|
&& (li == ri)
|
||||||
},
|
},
|
||||||
(&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
|
(&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
|
||||||
|
@ -1073,6 +1091,18 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
|
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hash_pat_expr(&mut self, lit: &PatExpr<'_>) {
|
||||||
|
std::mem::discriminant(&lit.kind).hash(&mut self.s);
|
||||||
|
match &lit.kind {
|
||||||
|
PatExprKind::Lit { lit, negated } => {
|
||||||
|
lit.node.hash(&mut self.s);
|
||||||
|
negated.hash(&mut self.s);
|
||||||
|
},
|
||||||
|
PatExprKind::ConstBlock(c) => self.hash_body(c.body),
|
||||||
|
PatExprKind::Path(qpath) => self.hash_qpath(qpath),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn hash_pat(&mut self, pat: &Pat<'_>) {
|
pub fn hash_pat(&mut self, pat: &Pat<'_>) {
|
||||||
std::mem::discriminant(&pat.kind).hash(&mut self.s);
|
std::mem::discriminant(&pat.kind).hash(&mut self.s);
|
||||||
match pat.kind {
|
match pat.kind {
|
||||||
|
@ -1084,7 +1114,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat),
|
PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat),
|
||||||
PatKind::Lit(expr) => self.hash_expr(expr),
|
PatKind::Expr(expr) => self.hash_pat_expr(expr),
|
||||||
PatKind::Or(pats) => {
|
PatKind::Or(pats) => {
|
||||||
for pat in pats {
|
for pat in pats {
|
||||||
self.hash_pat(pat);
|
self.hash_pat(pat);
|
||||||
|
@ -1093,10 +1123,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
PatKind::Path(ref qpath) => self.hash_qpath(qpath),
|
PatKind::Path(ref qpath) => self.hash_qpath(qpath),
|
||||||
PatKind::Range(s, e, i) => {
|
PatKind::Range(s, e, i) => {
|
||||||
if let Some(s) = s {
|
if let Some(s) = s {
|
||||||
self.hash_expr(s);
|
self.hash_pat_expr(s);
|
||||||
}
|
}
|
||||||
if let Some(e) = e {
|
if let Some(e) = e {
|
||||||
self.hash_expr(e);
|
self.hash_pat_expr(e);
|
||||||
}
|
}
|
||||||
std::mem::discriminant(&i).hash(&mut self.s);
|
std::mem::discriminant(&i).hash(&mut self.s);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1777,7 +1777,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true,
|
PatKind::Expr(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,8 @@ if let StmtKind::Let(local) = stmt.kind
|
||||||
}
|
}
|
||||||
if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind
|
if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind
|
||||||
&& let ExprKind::Let(let_expr) = cond.kind
|
&& let ExprKind::Let(let_expr) = cond.kind
|
||||||
&& let PatKind::Lit(lit_expr) = let_expr.pat.kind
|
&& let PatKind::Expr(lit_expr) = let_expr.pat.kind
|
||||||
&& let ExprKind::Lit(ref lit) = lit_expr.kind
|
&& let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
|
||||||
&& let LitKind::Bool(true) = lit.node
|
&& let LitKind::Bool(true) = lit.node
|
||||||
&& let ExprKind::Path(ref qpath) = let_expr.init.kind
|
&& let ExprKind::Path(ref qpath) = let_expr.init.kind
|
||||||
&& match_qpath(qpath, &["a"])
|
&& match_qpath(qpath, &["a"])
|
||||||
|
|
|
@ -76,8 +76,8 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While:
|
||||||
// report your lint here
|
// report your lint here
|
||||||
}
|
}
|
||||||
if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr)
|
if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr)
|
||||||
&& let PatKind::Lit(lit_expr) = let_pat.kind
|
&& let PatKind::Expr(lit_expr) = let_pat.kind
|
||||||
&& let ExprKind::Lit(ref lit) = lit_expr.kind
|
&& let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
|
||||||
&& let LitKind::Bool(true) = lit.node
|
&& let LitKind::Bool(true) = lit.node
|
||||||
&& let ExprKind::Path(ref qpath) = let_expr.kind
|
&& let ExprKind::Path(ref qpath) = let_expr.kind
|
||||||
&& match_qpath(qpath, &["a"])
|
&& match_qpath(qpath, &["a"])
|
||||||
|
|
|
@ -4,14 +4,14 @@ if let StmtKind::Let(local) = stmt.kind
|
||||||
&& let ExprKind::Lit(ref lit) = scrutinee.kind
|
&& let ExprKind::Lit(ref lit) = scrutinee.kind
|
||||||
&& let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
|
&& let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
|
||||||
&& arms.len() == 3
|
&& arms.len() == 3
|
||||||
&& let PatKind::Lit(lit_expr) = arms[0].pat.kind
|
&& let PatKind::Expr(lit_expr) = arms[0].pat.kind
|
||||||
&& let ExprKind::Lit(ref lit1) = lit_expr.kind
|
&& let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind
|
||||||
&& let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node
|
&& let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node
|
||||||
&& arms[0].guard.is_none()
|
&& arms[0].guard.is_none()
|
||||||
&& let ExprKind::Lit(ref lit2) = arms[0].body.kind
|
&& let ExprKind::Lit(ref lit2) = arms[0].body.kind
|
||||||
&& let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
|
&& let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
|
||||||
&& let PatKind::Lit(lit_expr1) = arms[1].pat.kind
|
&& let PatKind::Expr(lit_expr1) = arms[1].pat.kind
|
||||||
&& let ExprKind::Lit(ref lit3) = lit_expr1.kind
|
&& let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind
|
||||||
&& let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node
|
&& let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node
|
||||||
&& arms[1].guard.is_none()
|
&& arms[1].guard.is_none()
|
||||||
&& let ExprKind::Block(block, None) = arms[1].body.kind
|
&& let ExprKind::Block(block, None) = arms[1].body.kind
|
||||||
|
|
|
@ -23,8 +23,8 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
|
||||||
&& match_qpath(qpath, &["Test"])
|
&& match_qpath(qpath, &["Test"])
|
||||||
&& fields.len() == 1
|
&& fields.len() == 1
|
||||||
&& fields[0].ident.as_str() == "field"
|
&& fields[0].ident.as_str() == "field"
|
||||||
&& let PatKind::Lit(lit_expr) = fields[0].pat.kind
|
&& let PatKind::Expr(lit_expr) = fields[0].pat.kind
|
||||||
&& let ExprKind::Lit(ref lit) = lit_expr.kind
|
&& let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
|
||||||
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
|
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
|
||||||
&& arm.guard.is_none()
|
&& arm.guard.is_none()
|
||||||
&& let ExprKind::Block(block, None) = arm.body.kind
|
&& let ExprKind::Block(block, None) = arm.body.kind
|
||||||
|
@ -36,8 +36,8 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
|
||||||
if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind
|
if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind
|
||||||
&& match_qpath(qpath, &["TestTuple"])
|
&& match_qpath(qpath, &["TestTuple"])
|
||||||
&& fields.len() == 1
|
&& fields.len() == 1
|
||||||
&& let PatKind::Lit(lit_expr) = fields[0].kind
|
&& let PatKind::Expr(lit_expr) = fields[0].kind
|
||||||
&& let ExprKind::Lit(ref lit) = lit_expr.kind
|
&& let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
|
||||||
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
|
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
|
||||||
&& arm.guard.is_none()
|
&& arm.guard.is_none()
|
||||||
&& let ExprKind::Block(block, None) = arm.body.kind
|
&& let ExprKind::Block(block, None) = arm.body.kind
|
||||||
|
|
|
@ -42,7 +42,7 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
|
||||||
| ast::PatKind::Never
|
| ast::PatKind::Never
|
||||||
| ast::PatKind::Wild
|
| ast::PatKind::Wild
|
||||||
| ast::PatKind::Err(_)
|
| ast::PatKind::Err(_)
|
||||||
| ast::PatKind::Lit(_) => true,
|
| ast::PatKind::Expr(_) => true,
|
||||||
ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
|
ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
|
||||||
ast::PatKind::Struct(..)
|
ast::PatKind::Struct(..)
|
||||||
| ast::PatKind::MacCall(..)
|
| ast::PatKind::MacCall(..)
|
||||||
|
@ -293,7 +293,7 @@ impl Rewrite for Pat {
|
||||||
let path_str = rewrite_path(context, PathContext::Expr, q_self, path, shape)?;
|
let path_str = rewrite_path(context, PathContext::Expr, q_self, path, shape)?;
|
||||||
rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
|
rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
|
||||||
}
|
}
|
||||||
PatKind::Lit(ref expr) => expr.rewrite_result(context, shape),
|
PatKind::Expr(ref expr) => expr.rewrite_result(context, shape),
|
||||||
PatKind::Slice(ref slice_pat)
|
PatKind::Slice(ref slice_pat)
|
||||||
if context.config.style_edition() <= StyleEdition::Edition2021 =>
|
if context.config.style_edition() <= StyleEdition::Edition2021 =>
|
||||||
{
|
{
|
||||||
|
@ -530,7 +530,7 @@ pub(crate) fn can_be_overflowed_pat(
|
||||||
ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => {
|
ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => {
|
||||||
can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
|
can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
|
||||||
}
|
}
|
||||||
ast::PatKind::Lit(ref expr) => can_be_overflowed_expr(context, expr, len),
|
ast::PatKind::Expr(ref expr) => can_be_overflowed_expr(context, expr, len),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
TuplePatField::Dotdot(..) => false,
|
TuplePatField::Dotdot(..) => false,
|
||||||
|
|
|
@ -569,7 +569,7 @@ fn test_pat() {
|
||||||
c1!(pat, [ &pat ], "&pat");
|
c1!(pat, [ &pat ], "&pat");
|
||||||
c1!(pat, [ &mut pat ], "&mut pat");
|
c1!(pat, [ &mut pat ], "&mut pat");
|
||||||
|
|
||||||
// PatKind::Lit
|
// PatKind::Expr
|
||||||
c1!(pat, [ 1_000_i8 ], "1_000_i8");
|
c1!(pat, [ 1_000_i8 ], "1_000_i8");
|
||||||
|
|
||||||
// PatKind::Range
|
// PatKind::Range
|
||||||
|
|
|
@ -6,7 +6,7 @@ macro_rules! enum_number {
|
||||||
|
|
||||||
fn foo(value: i32) -> Option<$name> {
|
fn foo(value: i32) -> Option<$name> {
|
||||||
match value {
|
match value {
|
||||||
$( $value => Some($name::$variant), )* // PatKind::Lit
|
$( $value => Some($name::$variant), )* // PatKind::Expr
|
||||||
$( $value ..= 42 => Some($name::$variant), )* // PatKind::Range
|
$( $value ..= 42 => Some($name::$variant), )* // PatKind::Range
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Regression test for #135209.
|
||||||
|
// We ensure that we don't try to access fields on a non-struct pattern type.
|
||||||
|
fn main() {
|
||||||
|
if let <Vec<()> as Iterator>::Item { .. } = 1 {
|
||||||
|
//~^ ERROR E0658
|
||||||
|
//~| ERROR E0071
|
||||||
|
//~| ERROR E0277
|
||||||
|
x //~ ERROR E0425
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
error[E0425]: cannot find value `x` in this scope
|
||||||
|
--> $DIR/struct-pattern-on-non-struct-resolve-error.rs:8:9
|
||||||
|
|
|
||||||
|
LL | x
|
||||||
|
| ^ not found in this scope
|
||||||
|
|
||||||
|
error[E0658]: usage of qualified paths in this context is experimental
|
||||||
|
--> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12
|
||||||
|
|
|
||||||
|
LL | if let <Vec<()> as Iterator>::Item { .. } = 1 {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #86935 <https://github.com/rust-lang/rust/issues/86935> for more information
|
||||||
|
= help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0071]: expected struct, variant or union type, found inferred type
|
||||||
|
--> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12
|
||||||
|
|
|
||||||
|
LL | if let <Vec<()> as Iterator>::Item { .. } = 1 {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a struct
|
||||||
|
|
||||||
|
error[E0277]: `Vec<()>` is not an iterator
|
||||||
|
--> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12
|
||||||
|
|
|
||||||
|
LL | if let <Vec<()> as Iterator>::Item { .. } = 1 {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Vec<()>` is not an iterator
|
||||||
|
|
|
||||||
|
= help: the trait `Iterator` is not implemented for `Vec<()>`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0071, E0277, E0425, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0071`.
|
|
@ -3,6 +3,10 @@ struct Website {
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Foo {
|
||||||
|
Bar { a: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let website = Website {
|
let website = Website {
|
||||||
url: "http://www.example.com".into(),
|
url: "http://www.example.com".into(),
|
||||||
|
@ -18,4 +22,9 @@ fn main() {
|
||||||
println!("[{}]({})", title, url); //~ ERROR cannot find value `title` in this scope
|
println!("[{}]({})", title, url); //~ ERROR cannot find value `title` in this scope
|
||||||
//~^ NOTE not found in this scope
|
//~^ NOTE not found in this scope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let x = Foo::Bar { a: 1 };
|
||||||
|
if let Foo::Bar { .. } = x { //~ NOTE this pattern
|
||||||
|
println!("{a}"); //~ ERROR cannot find value `a` in this scope
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: expected `,`
|
error: expected `,`
|
||||||
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:12:31
|
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:16:31
|
||||||
|
|
|
|
||||||
LL | if let Website { url, Some(title) } = website {
|
LL | if let Website { url, Some(title) } = website {
|
||||||
| ------- ^
|
| ------- ^
|
||||||
|
@ -7,13 +7,21 @@ LL | if let Website { url, Some(title) } = website {
|
||||||
| while parsing the fields for this pattern
|
| while parsing the fields for this pattern
|
||||||
|
|
||||||
error[E0425]: cannot find value `title` in this scope
|
error[E0425]: cannot find value `title` in this scope
|
||||||
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:18:30
|
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:22:30
|
||||||
|
|
|
|
||||||
LL | if let Website { url, .. } = website {
|
LL | if let Website { url, .. } = website {
|
||||||
| ------------------- this pattern doesn't include `title`, which is available in `Website`
|
| ------------------- this pattern doesn't include `title`, which is available in `Website`
|
||||||
LL | println!("[{}]({})", title, url);
|
LL | println!("[{}]({})", title, url);
|
||||||
| ^^^^^ not found in this scope
|
| ^^^^^ not found in this scope
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0425]: cannot find value `a` in this scope
|
||||||
|
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:28:20
|
||||||
|
|
|
||||||
|
LL | if let Foo::Bar { .. } = x {
|
||||||
|
| --------------- this pattern doesn't include `a`, which is available in `Bar`
|
||||||
|
LL | println!("{a}");
|
||||||
|
| ^ help: a local variable with a similar name exists: `x`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0425`.
|
For more information about this error, try `rustc --explain E0425`.
|
||||||
|
|
|
@ -651,8 +651,8 @@ mod patterns {
|
||||||
let &mut pat;
|
let &mut pat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PatKind::Lit
|
/// PatKind::Expr
|
||||||
fn pat_lit() {
|
fn pat_expr() {
|
||||||
let 1_000_i8;
|
let 1_000_i8;
|
||||||
let -"";
|
let -"";
|
||||||
}
|
}
|
||||||
|
|
|
@ -567,8 +567,8 @@ mod patterns {
|
||||||
fn pat_deref() { let deref!(pat); }
|
fn pat_deref() { let deref!(pat); }
|
||||||
/// PatKind::Ref
|
/// PatKind::Ref
|
||||||
fn pat_ref() { let &pat; let &mut pat; }
|
fn pat_ref() { let &pat; let &mut pat; }
|
||||||
/// PatKind::Lit
|
/// PatKind::Expr
|
||||||
fn pat_lit() { let 1_000_i8; let -""; }
|
fn pat_expr() { let 1_000_i8; let -""; }
|
||||||
/// PatKind::Range
|
/// PatKind::Range
|
||||||
fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; }
|
fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; }
|
||||||
/// PatKind::Slice
|
/// PatKind::Slice
|
||||||
|
|
|
@ -14,4 +14,4 @@ extern crate std;
|
||||||
|
|
||||||
fn main() ({ } as ())
|
fn main() ({ } as ())
|
||||||
|
|
||||||
fn foo((-(128 as i8) as i8)...(127 as i8): i8) ({ } as ())
|
fn foo(-128...127: i8) ({ } as ())
|
||||||
|
|
|
@ -420,13 +420,20 @@ trigger_files = [
|
||||||
|
|
||||||
[autolabel."A-testsuite"]
|
[autolabel."A-testsuite"]
|
||||||
trigger_files = [
|
trigger_files = [
|
||||||
|
"src/bootstrap/src/core/build_steps/test.rs",
|
||||||
"src/ci",
|
"src/ci",
|
||||||
"src/tools/compiletest",
|
|
||||||
"src/tools/cargotest",
|
"src/tools/cargotest",
|
||||||
"src/tools/tidy",
|
"src/tools/compiletest",
|
||||||
|
"src/tools/miropt-test-tools",
|
||||||
"src/tools/remote-test-server",
|
"src/tools/remote-test-server",
|
||||||
"src/tools/remote-test-client",
|
"src/tools/remote-test-client",
|
||||||
"src/tools/tier-check"
|
"src/tools/rustdoc-gui-test",
|
||||||
|
"src/tools/suggest-tests",
|
||||||
|
]
|
||||||
|
|
||||||
|
[autolabel."A-tidy"]
|
||||||
|
trigger_files = [
|
||||||
|
"src/tools/tidy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[autolabel."A-meta"]
|
[autolabel."A-meta"]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue