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)
|
||||
- [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)
|
||||
- [`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>
|
||||
|
||||
|
|
|
@ -623,7 +623,7 @@ impl Pat {
|
|||
PatKind::Wild
|
||||
| PatKind::Rest
|
||||
| PatKind::Never
|
||||
| PatKind::Lit(_)
|
||||
| PatKind::Expr(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Ident(..)
|
||||
| PatKind::Path(..)
|
||||
|
@ -801,8 +801,8 @@ pub enum PatKind {
|
|||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(P<Pat>, Mutability),
|
||||
|
||||
/// A literal.
|
||||
Lit(P<Expr>),
|
||||
/// A literal, const block or path.
|
||||
Expr(P<Expr>),
|
||||
|
||||
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
|
||||
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);
|
||||
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) => {
|
||||
vis.visit_qself(qself);
|
||||
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));
|
||||
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) => {
|
||||
visit_opt!(visitor, visit_expr, lower_bound);
|
||||
visit_opt!(visitor, visit_expr, upper_bound);
|
||||
|
|
|
@ -102,17 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let kind = match &e.kind {
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
ExprKind::ConstBlock(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::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let count = self.lower_array_length_to_const_arg(count);
|
||||
|
@ -153,18 +143,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let ohs = self.lower_expr(ohs);
|
||||
hir::ExprKind::Unary(op, ohs)
|
||||
}
|
||||
ExprKind::Lit(token_lit) => {
|
||||
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::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),
|
||||
ExprKind::IncludedBytes(bytes) => {
|
||||
let lit = self.arena.alloc(respan(
|
||||
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 {
|
||||
match u {
|
||||
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>) {
|
||||
self.insert(field.span, field.hir_id, Node::PatField(field));
|
||||
self.with_parent(field.hir_id, |this| {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![warn(unreachable_pub)]
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
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 super::errors::{
|
||||
|
@ -35,8 +38,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
lower_sub,
|
||||
);
|
||||
}
|
||||
PatKind::Lit(e) => {
|
||||
break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
|
||||
PatKind::Expr(e) => {
|
||||
break hir::PatKind::Expr(self.lower_expr_within_pat(e, false));
|
||||
}
|
||||
PatKind::TupleStruct(qself, path, pats) => {
|
||||
let qpath = self.lower_qpath(
|
||||
|
@ -367,24 +370,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// }
|
||||
// m!(S);
|
||||
// ```
|
||||
fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
|
||||
match &expr.kind {
|
||||
ExprKind::Lit(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::IncludedBytes(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => {}
|
||||
ExprKind::Path(..) if allow_paths => {}
|
||||
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
|
||||
fn lower_expr_within_pat(
|
||||
&mut self,
|
||||
expr: &Expr,
|
||||
allow_paths: bool,
|
||||
) -> &'hir hir::PatExpr<'hir> {
|
||||
let err = |guar| hir::PatExprKind::Lit {
|
||||
lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))),
|
||||
negated: false,
|
||||
};
|
||||
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 guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
|
||||
span: expr.span,
|
||||
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);
|
||||
}
|
||||
}
|
||||
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, .. }) => {
|
||||
if let Some(e) = begin {
|
||||
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::places_conflict::{PlaceConflictBias, places_conflict};
|
||||
pub use super::polonius::legacy::{
|
||||
AllFacts as PoloniusInput, LocationTable, PoloniusOutput, PoloniusRegionVid, RichLocation,
|
||||
RustcFacts,
|
||||
PoloniusFacts as PoloniusInput, PoloniusLocationTable, PoloniusOutput, PoloniusRegionVid,
|
||||
RichLocation, RustcFacts,
|
||||
};
|
||||
pub use super::region_infer::RegionInferenceContext;
|
||||
|
||||
|
@ -33,7 +33,7 @@ pub enum ConsumerOptions {
|
|||
/// without significant slowdowns.
|
||||
///
|
||||
/// 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
|
||||
/// one may want to avoid due to performance issues on large bodies.
|
||||
PoloniusInputFacts,
|
||||
|
@ -71,7 +71,7 @@ pub struct BodyWithBorrowckFacts<'tcx> {
|
|||
/// The table that maps Polonius points to locations in the table.
|
||||
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
||||
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
||||
pub location_table: Option<LocationTable>,
|
||||
pub location_table: Option<PoloniusLocationTable>,
|
||||
/// Polonius input facts.
|
||||
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
||||
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
||||
|
|
|
@ -60,7 +60,7 @@ use crate::diagnostics::{
|
|||
use crate::path_utils::*;
|
||||
use crate::place_ext::PlaceExt;
|
||||
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::region_infer::RegionInferenceContext;
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
@ -179,7 +179,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
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 promoted_move_data = promoted
|
||||
|
@ -250,7 +250,8 @@ fn do_mir_borrowck<'tcx>(
|
|||
infcx: &infcx,
|
||||
body: promoted_body,
|
||||
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,
|
||||
fn_self_span_reported: Default::default(),
|
||||
locals_are_invalidated_at_exit,
|
||||
|
@ -516,7 +517,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
|
||||
/// Map from MIR `Location` to `LocationIndex`; created
|
||||
/// when MIR borrowck begins.
|
||||
location_table: &'a LocationTable,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
|
||||
movable_coroutine: bool,
|
||||
/// 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::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
|
||||
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::type_check::{self, MirTypeckResults};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
@ -39,7 +41,7 @@ use crate::{BorrowckInferCtxt, polonius, renumber};
|
|||
pub(crate) struct NllOutput<'tcx> {
|
||||
pub regioncx: RegionInferenceContext<'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 opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
|
||||
pub nll_errors: RegionErrors<'tcx>,
|
||||
|
@ -80,7 +82,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
universal_regions: UniversalRegions<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
|
@ -91,10 +93,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
|| is_polonius_legacy_enabled;
|
||||
let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
|
||||
|| is_polonius_legacy_enabled;
|
||||
let mut all_facts =
|
||||
(polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
|
||||
let mut polonius_facts =
|
||||
(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.
|
||||
let MirTypeckResults {
|
||||
|
@ -109,10 +111,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
universal_regions,
|
||||
location_table,
|
||||
borrow_set,
|
||||
&mut all_facts,
|
||||
&mut polonius_facts,
|
||||
flow_inits,
|
||||
move_data,
|
||||
Rc::clone(&elements),
|
||||
Rc::clone(&location_map),
|
||||
);
|
||||
|
||||
// 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.
|
||||
polonius::legacy::emit_facts(
|
||||
&mut all_facts,
|
||||
&mut polonius_facts,
|
||||
infcx.tcx,
|
||||
location_table,
|
||||
body,
|
||||
|
@ -137,7 +139,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
var_infos,
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
elements,
|
||||
location_map,
|
||||
);
|
||||
|
||||
// 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.
|
||||
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 {
|
||||
let def_id = body.source.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)
|
||||
.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 {
|
||||
|
@ -162,7 +164,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
let algorithm = Algorithm::from_str(&algorithm).unwrap();
|
||||
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
|
||||
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 {
|
||||
None
|
||||
}
|
||||
|
@ -182,7 +184,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
NllOutput {
|
||||
regioncx,
|
||||
opaque_type_values: remapped_opaque_tys,
|
||||
polonius_input: all_facts.map(Box::new),
|
||||
polonius_input: polonius_facts.map(Box::new),
|
||||
polonius_output,
|
||||
opt_closure_req: closure_region_requirements,
|
||||
nll_errors,
|
||||
|
|
|
@ -4,16 +4,16 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_mir_dataflow::move_paths::{LookupResult, MoveData};
|
||||
use tracing::debug;
|
||||
|
||||
use super::{AllFacts, LocationIndex, LocationTable};
|
||||
use super::{LocationIndex, PoloniusFacts, PoloniusLocationTable};
|
||||
use crate::def_use::{self, DefUse};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
||||
/// Emit polonius facts for variable defs, uses, drops, and path accesses.
|
||||
pub(crate) fn emit_access_facts<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
body: &Body<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
move_data: &MoveData<'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) {
|
||||
|
@ -31,9 +31,9 @@ pub(crate) fn emit_access_facts<'tcx>(
|
|||
|
||||
/// MIR visitor extracting point-wise facts about accesses.
|
||||
struct AccessFactsExtractor<'a, 'tcx> {
|
||||
facts: &'a mut AllFacts,
|
||||
facts: &'a mut PoloniusFacts,
|
||||
move_data: &'a MoveData<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
}
|
||||
|
||||
impl<'tcx> AccessFactsExtractor<'_, 'tcx> {
|
||||
|
|
|
@ -4,13 +4,13 @@ use std::fs::{self, File};
|
|||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use polonius_engine::{AllFacts as PoloniusFacts, Atom, Output};
|
||||
use polonius_engine::{AllFacts, Atom, Output};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::mir::Local;
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::MovePathIndex;
|
||||
|
||||
use super::{LocationIndex, LocationTable};
|
||||
use super::{LocationIndex, PoloniusLocationTable};
|
||||
use crate::BorrowIndex;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -49,11 +49,11 @@ impl polonius_engine::FactTypes for RustcFacts {
|
|||
type Path = MovePathIndex;
|
||||
}
|
||||
|
||||
pub type AllFacts = PoloniusFacts<RustcFacts>;
|
||||
pub type PoloniusFacts = AllFacts<RustcFacts>;
|
||||
|
||||
#[extension(pub(crate) trait AllFactsExt)]
|
||||
impl AllFacts {
|
||||
/// Returns `true` if there is a need to gather `AllFacts` given the
|
||||
#[extension(pub(crate) trait PoloniusFactsExt)]
|
||||
impl PoloniusFacts {
|
||||
/// Returns `true` if there is a need to gather `PoloniusFacts` given the
|
||||
/// current `-Z` flags.
|
||||
fn enabled(tcx: TyCtxt<'_>) -> bool {
|
||||
tcx.sess.opts.unstable_opts.nll_facts
|
||||
|
@ -63,7 +63,7 @@ impl AllFacts {
|
|||
fn write_to_dir(
|
||||
&self,
|
||||
dir: impl AsRef<Path>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let dir: &Path = dir.as_ref();
|
||||
fs::create_dir_all(dir)?;
|
||||
|
@ -119,7 +119,7 @@ impl Atom for LocationIndex {
|
|||
}
|
||||
|
||||
struct FactWriter<'w> {
|
||||
location_table: &'w LocationTable,
|
||||
location_table: &'w PoloniusLocationTable,
|
||||
dir: &'w Path,
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ trait FactRow {
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ impl FactRow for PoloniusRegionVid {
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[self])
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ where
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1])
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ where
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1, &self.2])
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ where
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ where
|
|||
|
||||
fn write_row(
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
columns: &[&dyn FactCell],
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
for (index, c) in columns.iter().enumerate() {
|
||||
|
@ -213,41 +213,41 @@ fn write_row(
|
|||
}
|
||||
|
||||
trait FactCell {
|
||||
fn to_string(&self, location_table: &LocationTable) -> String;
|
||||
fn to_string(&self, location_table: &PoloniusLocationTable) -> String;
|
||||
}
|
||||
|
||||
impl FactCell for BorrowIndex {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for Local {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for MovePathIndex {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for PoloniusRegionVid {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for RegionVid {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use rustc_middle::mir::{
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::debug;
|
||||
|
||||
use super::{AllFacts, LocationTable};
|
||||
use super::{PoloniusFacts, PoloniusLocationTable};
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::path_utils::*;
|
||||
use crate::{
|
||||
|
@ -22,9 +22,9 @@ use crate::{
|
|||
/// Emit `loan_invalidated_at` facts.
|
||||
pub(super) fn emit_loan_invalidations<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
body: &Body<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
) {
|
||||
let dominators = body.basic_blocks.dominators();
|
||||
|
@ -35,9 +35,9 @@ pub(super) fn emit_loan_invalidations<'tcx>(
|
|||
|
||||
struct LoanInvalidationsGenerator<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &'a mut AllFacts,
|
||||
facts: &'a mut PoloniusFacts,
|
||||
body: &'a Body<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
dominators: &'a Dominators<BasicBlock>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
}
|
||||
|
|
|
@ -6,16 +6,16 @@ use rustc_middle::mir::{
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::debug;
|
||||
|
||||
use super::{AllFacts, LocationTable};
|
||||
use super::{PoloniusFacts, PoloniusLocationTable};
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::places_conflict;
|
||||
|
||||
/// Emit `loan_killed_at` and `cfg_edge` facts at the same time.
|
||||
pub(super) fn emit_loan_kills<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
body: &Body<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
) {
|
||||
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> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &'a mut AllFacts,
|
||||
location_table: &'a LocationTable,
|
||||
facts: &'a mut PoloniusFacts,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use tracing::debug;
|
|||
/// granularity through outlives relations; however, the rich location
|
||||
/// table serves another purpose: it compresses locations from
|
||||
/// multiple words into a single u32.
|
||||
pub struct LocationTable {
|
||||
pub struct PoloniusLocationTable {
|
||||
num_points: usize,
|
||||
statements_before_block: IndexVec<BasicBlock, usize>,
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ pub enum RichLocation {
|
|||
Mid(Location),
|
||||
}
|
||||
|
||||
impl LocationTable {
|
||||
impl PoloniusLocationTable {
|
||||
pub(crate) fn new(body: &Body<'_>) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block = body
|
||||
|
@ -43,8 +43,8 @@ impl LocationTable {
|
|||
})
|
||||
.collect();
|
||||
|
||||
debug!("LocationTable(statements_before_block={:#?})", statements_before_block);
|
||||
debug!("LocationTable: num_points={:#?}", num_points);
|
||||
debug!("PoloniusLocationTable(statements_before_block={:#?})", statements_before_block);
|
||||
debug!("PoloniusLocationTable: num_points={:#?}", num_points);
|
||||
|
||||
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.
|
||||
pub(crate) fn emit_facts<'tcx>(
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
facts: &mut Option<PoloniusFacts>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
body: &Body<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
universal_region_relations: &UniversalRegionRelations<'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.
|
||||
return;
|
||||
};
|
||||
|
@ -67,9 +67,9 @@ pub(crate) fn emit_facts<'tcx>(
|
|||
|
||||
/// Emit facts needed for move/init analysis: moves and assignments.
|
||||
fn emit_move_facts(
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
body: &Body<'_>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
move_data: &MoveData<'_>,
|
||||
) {
|
||||
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.
|
||||
fn emit_universal_region_facts(
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
borrow_set: &BorrowSet<'_>,
|
||||
universal_region_relations: &UniversalRegionRelations<'_>,
|
||||
) {
|
||||
|
@ -187,10 +187,10 @@ pub(crate) fn emit_drop_facts<'tcx>(
|
|||
local: Local,
|
||||
kind: &GenericArg<'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
facts: &mut Option<PoloniusFacts>,
|
||||
) {
|
||||
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");
|
||||
tcx.for_each_free_region(kind, |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
|
||||
/// closure.
|
||||
fn emit_outlives_facts<'tcx>(
|
||||
facts: &mut AllFacts,
|
||||
location_table: &LocationTable,
|
||||
facts: &mut PoloniusFacts,
|
||||
location_table: &PoloniusLocationTable,
|
||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||
) {
|
||||
facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map(
|
||||
|
|
|
@ -392,7 +392,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
var_infos: VarInfos,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
) -> Self {
|
||||
let universal_regions = &universal_region_relations.universal_regions;
|
||||
let MirTypeckRegionConstraints {
|
||||
|
@ -436,7 +436,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
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() {
|
||||
let scc = constraint_sccs.scc(region);
|
||||
|
|
|
@ -38,7 +38,7 @@ pub(crate) enum RegionElement {
|
|||
/// an interval matrix storing liveness ranges for each region-vid.
|
||||
pub(crate) struct LivenessValues {
|
||||
/// 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
|
||||
/// currently only used for validating promoteds (which don't care about more precise tracking).
|
||||
|
@ -77,11 +77,11 @@ impl LiveLoans {
|
|||
|
||||
impl LivenessValues {
|
||||
/// 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 {
|
||||
live_regions: None,
|
||||
points: Some(SparseIntervalMatrix::new(elements.num_points())),
|
||||
elements,
|
||||
points: Some(SparseIntervalMatrix::new(location_map.num_points())),
|
||||
location_map,
|
||||
loans: None,
|
||||
}
|
||||
}
|
||||
|
@ -90,11 +90,11 @@ impl LivenessValues {
|
|||
///
|
||||
/// Unlike `with_specific_points`, does not track exact locations where something is live, only
|
||||
/// 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 {
|
||||
live_regions: Some(Default::default()),
|
||||
points: None,
|
||||
elements,
|
||||
location_map,
|
||||
loans: None,
|
||||
}
|
||||
}
|
||||
|
@ -122,11 +122,11 @@ impl LivenessValues {
|
|||
|
||||
/// Records `region` as being live at the given `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);
|
||||
if let Some(points) = &mut self.points {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ impl LivenessValues {
|
|||
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
|
||||
if let Some(this) = &mut self.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);
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ impl LivenessValues {
|
|||
|
||||
/// Returns whether `region` is marked live at the given `location`.
|
||||
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 {
|
||||
points.row(region).is_some_and(|r| r.contains(point))
|
||||
} else {
|
||||
|
@ -191,25 +191,26 @@ impl LivenessValues {
|
|||
.row(region)
|
||||
.into_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
|
||||
/// live.
|
||||
pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
|
||||
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]
|
||||
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
|
||||
self.elements.point_from_location(location)
|
||||
self.location_map.point_from_location(location)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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`.
|
||||
|
@ -272,7 +273,7 @@ impl PlaceholderIndices {
|
|||
/// because (since it is returned) it must live for at least `'a`. But
|
||||
/// it would also contain various points from within the function.
|
||||
pub(crate) struct RegionValues<N: Idx> {
|
||||
elements: Rc<DenseLocationMap>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
placeholder_indices: PlaceholderIndices,
|
||||
points: SparseIntervalMatrix<N, PointIndex>,
|
||||
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
|
||||
/// empty set of points and no causal information.
|
||||
pub(crate) fn new(
|
||||
elements: Rc<DenseLocationMap>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
num_universal_regions: usize,
|
||||
placeholder_indices: PlaceholderIndices,
|
||||
) -> Self {
|
||||
let num_points = elements.num_points();
|
||||
let num_points = location_map.num_points();
|
||||
let num_placeholders = placeholder_indices.len();
|
||||
Self {
|
||||
elements,
|
||||
location_map,
|
||||
points: SparseIntervalMatrix::new(num_points),
|
||||
placeholder_indices,
|
||||
free_regions: SparseBitMatrix::new(num_universal_regions),
|
||||
|
@ -336,7 +337,7 @@ impl<N: Idx> RegionValues<N> {
|
|||
end: usize,
|
||||
) -> Option<usize> {
|
||||
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 end = block.plus(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 {
|
||||
self.points.row(r).into_iter().flat_map(move |set| {
|
||||
set.iter()
|
||||
.take_while(move |&p| self.elements.point_in_range(p))
|
||||
.map(move |p| self.elements.to_location(p))
|
||||
.take_while(move |&p| self.location_map.point_in_range(p))
|
||||
.map(move |p| self.location_map.to_location(p))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -430,12 +431,12 @@ pub(crate) trait ToElementIndex: Debug + Copy {
|
|||
|
||||
impl ToElementIndex for Location {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -464,14 +465,14 @@ impl ToElementIndex for ty::PlaceholderRegion {
|
|||
|
||||
/// For debugging purposes, returns a pretty-printed string of the given points.
|
||||
pub(crate) fn pretty_print_points(
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
points: impl IntoIterator<Item = PointIndex>,
|
||||
) -> String {
|
||||
pretty_print_region_elements(
|
||||
points
|
||||
.into_iter()
|
||||
.take_while(|&p| elements.point_in_range(p))
|
||||
.map(|p| elements.to_location(p))
|
||||
.take_while(|&p| location_map.point_in_range(p))
|
||||
.map(|p| location_map.to_location(p))
|
||||
.map(RegionElement::Location),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ impl<'a> Iterator for AppearancesIter<'a> {
|
|||
impl LocalUseMap {
|
||||
pub(crate) fn build(
|
||||
live_locals: &[Local],
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
body: &Body<'_>,
|
||||
) -> Self {
|
||||
let nones = IndexVec::from_elem(None, &body.local_decls);
|
||||
|
@ -101,7 +101,7 @@ impl LocalUseMap {
|
|||
IndexVec::from_elem(false, &body.local_decls);
|
||||
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);
|
||||
|
||||
local_use_map
|
||||
|
@ -125,7 +125,7 @@ impl LocalUseMap {
|
|||
|
||||
struct LocalUseMapBuild<'me> {
|
||||
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
|
||||
// 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::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
|
||||
.local_use_map
|
||||
.appearances
|
||||
|
|
|
@ -32,7 +32,7 @@ mod trace;
|
|||
pub(super) fn generate<'a, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) {
|
||||
|
@ -49,7 +49,7 @@ pub(super) fn generate<'a, 'tcx>(
|
|||
trace::trace(
|
||||
typeck,
|
||||
body,
|
||||
elements,
|
||||
location_map,
|
||||
flow_inits,
|
||||
move_data,
|
||||
relevant_live_locals,
|
||||
|
|
|
@ -37,13 +37,13 @@ use crate::type_check::{NormalizeLocation, TypeChecker};
|
|||
pub(super) fn trace<'a, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
relevant_live_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.
|
||||
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||
|
@ -79,7 +79,7 @@ pub(super) fn trace<'a, 'tcx>(
|
|||
typeck,
|
||||
body,
|
||||
flow_inits,
|
||||
elements,
|
||||
location_map,
|
||||
local_use_map,
|
||||
move_data,
|
||||
drop_data: FxIndexMap::default(),
|
||||
|
@ -100,7 +100,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> {
|
|||
typeck: &'a mut TypeChecker<'typeck, 'tcx>,
|
||||
|
||||
/// Defines the `PointIndex` mapping
|
||||
elements: &'a DenseLocationMap,
|
||||
location_map: &'a DenseLocationMap,
|
||||
|
||||
/// MIR we are analyzing.
|
||||
body: &'a Body<'tcx>,
|
||||
|
@ -149,7 +149,7 @@ struct LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
|
||||
impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||
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 {
|
||||
cx,
|
||||
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]) {
|
||||
// This collect is more necessary than immediately apparent
|
||||
// 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.
|
||||
// FIXME for future hackers: investigate whether this is
|
||||
// actually necessary; these facts come from Polonius
|
||||
// and probably maybe plausibly does not need to go back in.
|
||||
// It may be necessary to just pick out the parts of
|
||||
// `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 relevant_live_locals: FxIndexSet<_> =
|
||||
relevant_live_locals.iter().copied().collect();
|
||||
|
@ -240,7 +240,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
.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 {
|
||||
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
|
||||
// * Exclusively, the previous definition (if it's in this block)
|
||||
// * 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_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
|
||||
// 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.cx.body.basic_blocks.predecessors()[block]
|
||||
.iter()
|
||||
.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.
|
||||
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,);
|
||||
|
||||
if self.cx.initialized_at_terminator(location.block, mpi)
|
||||
|
@ -367,7 +367,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
debug!(
|
||||
"compute_drop_live_points_for_block(mpi={:?}, term_point={:?})",
|
||||
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
|
||||
|
@ -377,12 +377,15 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
// Otherwise, scan backwards through the statements in the
|
||||
// block. One of them may be either a definition or use
|
||||
// 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,);
|
||||
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() {
|
||||
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) {
|
||||
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_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*
|
||||
// our value or is a "normal use", then stop.
|
||||
|
@ -523,7 +526,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
|||
/// points `live_at`.
|
||||
fn add_use_live_facts_for(&mut self, value: Ty<'tcx>, live_at: &IntervalSet<PointIndex>) {
|
||||
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`
|
||||
|
@ -547,7 +550,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
|||
dropped_local,
|
||||
dropped_ty,
|
||||
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({
|
||||
|
@ -574,19 +577,19 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
|||
// All things in the `outlives` array may be touched by
|
||||
// the destructor and must be live at this point.
|
||||
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(
|
||||
self.typeck.tcx(),
|
||||
dropped_local,
|
||||
&kind,
|
||||
self.typeck.universal_regions,
|
||||
self.typeck.all_facts,
|
||||
self.typeck.polonius_facts,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn make_all_regions_live(
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
|
||||
live_at: &IntervalSet<PointIndex>,
|
||||
|
@ -594,7 +597,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
|||
debug!("make_all_regions_live(value={:?})", value);
|
||||
debug!(
|
||||
"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 {
|
||||
|
|
|
@ -49,7 +49,7 @@ use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
|
|||
use crate::diagnostics::UniverseInfo;
|
||||
use crate::member_constraints::MemberConstraintSet;
|
||||
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::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
@ -98,29 +98,29 @@ mod relate_tys;
|
|||
/// - `body` -- MIR body to type-check
|
||||
/// - `promoted` -- map of promoted constants within `body`
|
||||
/// - `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`
|
||||
/// - `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
|
||||
/// - `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>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
polonius_facts: &mut Option<PoloniusFacts>,
|
||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
||||
let mut constraints = MirTypeckRegionConstraints {
|
||||
placeholder_indices: PlaceholderIndices::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(),
|
||||
member_constraints: MemberConstraintSet::default(),
|
||||
type_tests: Vec::default(),
|
||||
|
@ -165,7 +165,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
reported_errors: Default::default(),
|
||||
universal_regions: &universal_region_relations.universal_regions,
|
||||
location_table,
|
||||
all_facts,
|
||||
polonius_facts,
|
||||
borrow_set,
|
||||
constraints: &mut constraints,
|
||||
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.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 =
|
||||
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
|
||||
// modify their locations.
|
||||
let all_facts = &mut None;
|
||||
let polonius_facts = &mut None;
|
||||
let mut constraints = Default::default();
|
||||
let mut liveness_constraints =
|
||||
LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body)));
|
||||
// Don't try to add borrow_region facts for the promoted MIR
|
||||
|
||||
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.liveness_constraints, &mut liveness_constraints);
|
||||
};
|
||||
|
@ -560,8 +560,8 @@ struct TypeChecker<'a, 'tcx> {
|
|||
implicit_region_bound: ty::Region<'tcx>,
|
||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
all_facts: &'a mut Option<AllFacts>,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
polonius_facts: &'a mut Option<PoloniusFacts>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
/// 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>,
|
||||
) {
|
||||
// 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
|
||||
// linking the loan to the region (in some cases, though,
|
||||
// there is no loan associated with this borrow expression --
|
||||
// that occurs when we are borrowing an unsafe place, for
|
||||
// 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");
|
||||
if let Some(borrow_index) = borrow_set.get_index_of(&location) {
|
||||
let region_vid = borrow_region.as_var();
|
||||
all_facts.loan_issued_at.push((
|
||||
polonius_facts.loan_issued_at.push((
|
||||
region_vid.into(),
|
||||
borrow_index,
|
||||
location_table.mid_index(location),
|
||||
|
|
|
@ -522,7 +522,7 @@ impl MacResult for MacEager {
|
|||
return Some(P(ast::Pat {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: e.span,
|
||||
kind: PatKind::Lit(e),
|
||||
kind: PatKind::Expr(e),
|
||||
tokens: None,
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -486,7 +486,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
self.pat(span, PatKind::Wild)
|
||||
}
|
||||
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> {
|
||||
self.pat_ident_binding_mode(span, ident, ast::BindingMode::NONE)
|
||||
|
|
|
@ -1386,7 +1386,7 @@ impl<'hir> Pat<'hir> {
|
|||
|
||||
use PatKind::*;
|
||||
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),
|
||||
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)),
|
||||
|
@ -1413,7 +1413,7 @@ impl<'hir> Pat<'hir> {
|
|||
|
||||
use PatKind::*;
|
||||
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),
|
||||
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)),
|
||||
|
@ -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)]
|
||||
pub enum PatKind<'hir> {
|
||||
/// Represents a wildcard pattern (i.e., `_`).
|
||||
|
@ -1563,14 +1583,14 @@ pub enum PatKind<'hir> {
|
|||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(&'hir Pat<'hir>, Mutability),
|
||||
|
||||
/// A literal.
|
||||
Lit(&'hir Expr<'hir>),
|
||||
/// A literal, const block or path.
|
||||
Expr(&'hir PatExpr<'hir>),
|
||||
|
||||
/// A guard pattern (e.g., `x if guard(x)`).
|
||||
Guard(&'hir Pat<'hir>, &'hir Expr<'hir>),
|
||||
|
||||
/// 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)?]`.
|
||||
///
|
||||
|
@ -4144,6 +4164,10 @@ pub enum Node<'hir> {
|
|||
OpaqueTy(&'hir OpaqueTy<'hir>),
|
||||
Pat(&'hir Pat<'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>),
|
||||
Block(&'hir Block<'hir>),
|
||||
LetStmt(&'hir LetStmt<'hir>),
|
||||
|
@ -4200,6 +4224,7 @@ impl<'hir> Node<'hir> {
|
|||
| Node::Block(..)
|
||||
| Node::Ctor(..)
|
||||
| Node::Pat(..)
|
||||
| Node::PatExpr(..)
|
||||
| Node::Arm(..)
|
||||
| Node::LetStmt(..)
|
||||
| Node::Crate(..)
|
||||
|
|
|
@ -342,6 +342,9 @@ pub trait Visitor<'v>: Sized {
|
|||
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
|
||||
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 {
|
||||
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));
|
||||
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, _) => {
|
||||
visit_opt!(visitor, visit_expr, lower_bound);
|
||||
visit_opt!(visitor, visit_expr, upper_bound);
|
||||
visit_opt!(visitor, visit_pat_expr, lower_bound);
|
||||
visit_opt!(visitor, visit_pat_expr, upper_bound);
|
||||
}
|
||||
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
try_visit!(visitor.visit_id(constant.hir_id));
|
||||
visitor.visit_nested_body(constant.body)
|
||||
|
|
|
@ -704,7 +704,7 @@ fn resolve_local<'tcx>(
|
|||
| PatKind::Wild
|
||||
| PatKind::Never
|
||||
| PatKind::Path(_)
|
||||
| PatKind::Lit(_)
|
||||
| PatKind::Expr(_)
|
||||
| PatKind::Range(_, _, _)
|
||||
| PatKind::Err(_) => false,
|
||||
}
|
||||
|
|
|
@ -2449,17 +2449,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Ty::new_error(tcx, err)
|
||||
}
|
||||
hir::PatKind::Range(start, end, include_end) => {
|
||||
let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> {
|
||||
let (expr, neg) = match expr.kind {
|
||||
hir::ExprKind::Unary(hir::UnOp::Neg, negated) => {
|
||||
(negated, Some((expr.hir_id, expr.span)))
|
||||
}
|
||||
_ => (expr, None),
|
||||
};
|
||||
let (c, c_ty) = match &expr.kind {
|
||||
hir::ExprKind::Lit(lit) => {
|
||||
let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
|
||||
let (c, c_ty) = match expr.kind {
|
||||
hir::PatExprKind::Lit { lit, negated } => {
|
||||
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) {
|
||||
Ok(c) => c,
|
||||
Err(LitToConstError::Reported(err)) => {
|
||||
|
@ -2470,17 +2464,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
(ct, ty)
|
||||
}
|
||||
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
hir::PatExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
path @ &hir::Path {
|
||||
res: Res::Def(DefKind::ConstParam, def_id),
|
||||
..
|
||||
},
|
||||
)) => {
|
||||
let _ = self.prohibit_generic_args(
|
||||
match self.prohibit_generic_args(
|
||||
path.segments.iter(),
|
||||
GenericsArgsErrExtend::Param(def_id),
|
||||
);
|
||||
) {
|
||||
Ok(()) => {
|
||||
let ty = tcx
|
||||
.type_of(def_id)
|
||||
.no_bound_vars()
|
||||
|
@ -2488,6 +2483,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let ct = self.lower_const_param(def_id, expr.hir_id);
|
||||
(ct, ty)
|
||||
}
|
||||
Err(guar) => (
|
||||
ty::Const::new_error(tcx, guar),
|
||||
Ty::new_error(tcx, guar),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
let err = tcx
|
||||
|
@ -2497,9 +2498,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
};
|
||||
self.record_ty(expr.hir_id, c_ty, expr.span);
|
||||
if let Some((id, span)) = neg {
|
||||
self.record_ty(id, c_ty, span);
|
||||
}
|
||||
c
|
||||
};
|
||||
|
||||
|
|
|
@ -199,6 +199,7 @@ impl<'a> State<'a> {
|
|||
Node::OpaqueTy(o) => self.print_opaque_ty(o),
|
||||
Node::Pat(a) => self.print_pat(a),
|
||||
Node::PatField(a) => self.print_patfield(a),
|
||||
Node::PatExpr(a) => self.print_pat_expr(a),
|
||||
Node::Arm(a) => self.print_arm(a),
|
||||
Node::Infer(_) => self.word("_"),
|
||||
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<'_>) {
|
||||
self.maybe_print_comment(pat.span.lo());
|
||||
self.ann.pre(self, AnnNode::Pat(pat));
|
||||
|
@ -1966,17 +1980,17 @@ impl<'a> State<'a> {
|
|||
self.pclose();
|
||||
}
|
||||
}
|
||||
PatKind::Lit(e) => self.print_expr(e),
|
||||
PatKind::Expr(e) => self.print_pat_expr(e),
|
||||
PatKind::Range(begin, end, end_kind) => {
|
||||
if let Some(expr) = begin {
|
||||
self.print_expr(expr);
|
||||
self.print_pat_expr(expr);
|
||||
}
|
||||
match end_kind {
|
||||
RangeEnd::Included => self.word("..."),
|
||||
RangeEnd::Excluded => self.word(".."),
|
||||
}
|
||||
if let Some(expr) = end {
|
||||
self.print_expr(expr);
|
||||
self.print_pat_expr(expr);
|
||||
}
|
||||
}
|
||||
PatKind::Slice(before, slice, after) => {
|
||||
|
|
|
@ -430,6 +430,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| hir::Node::AssocItemConstraint(_)
|
||||
| hir::Node::TraitRef(_)
|
||||
| hir::Node::PatField(_)
|
||||
| hir::Node::PatExpr(_)
|
||||
| hir::Node::LetStmt(_)
|
||||
| hir::Node::Synthetic
|
||||
| hir::Node::Err(_)
|
||||
|
@ -484,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| hir::PatKind::Box(_)
|
||||
| hir::PatKind::Ref(_, _)
|
||||
| hir::PatKind::Deref(_)
|
||||
| hir::PatKind::Lit(_)
|
||||
| hir::PatKind::Expr(_)
|
||||
| hir::PatKind::Range(_, _, _)
|
||||
| hir::PatKind::Slice(_, _, _)
|
||||
| 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
|
||||
// a type parameter outlives the moment of instantiation.
|
||||
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
|
||||
}
|
||||
|
@ -1796,7 +1797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_expr_const_block(
|
||||
pub(super) fn check_expr_const_block(
|
||||
&self,
|
||||
block: &'tcx hir::ConstBlock,
|
||||
expected: Expectation<'tcx>,
|
||||
|
|
|
@ -595,7 +595,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
let place_ty = place.place.ty();
|
||||
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
|
||||
// to borrow discr.
|
||||
needs_to_be_read = true;
|
||||
|
@ -1803,7 +1803,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
|
||||
PatKind::Path(_)
|
||||
| PatKind::Binding(.., None)
|
||||
| PatKind::Lit(..)
|
||||
| PatKind::Expr(..)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Never
|
||||
| PatKind::Wild
|
||||
|
|
|
@ -577,11 +577,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// 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| {
|
||||
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,
|
||||
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),
|
||||
};
|
||||
|
||||
|
|
|
@ -611,7 +611,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
|
||||
// this is a projection from a trait reference, so we have to
|
||||
// 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
|
||||
// implied by the args being well-formed because of inherent
|
||||
|
|
|
@ -170,6 +170,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
span,
|
||||
..
|
||||
})
|
||||
| hir::Node::PatExpr(&hir::PatExpr {
|
||||
kind: hir::PatExprKind::Path(QPath::TypeRelative(rcvr, segment)),
|
||||
span,
|
||||
..
|
||||
})
|
||||
| hir::Node::Pat(&hir::Pat {
|
||||
kind:
|
||||
hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))
|
||||
|
|
|
@ -30,6 +30,7 @@ use tracing::{debug, instrument, trace};
|
|||
use ty::VariantDef;
|
||||
|
||||
use super::report_unexpected_variant_res;
|
||||
use crate::expectation::Expectation;
|
||||
use crate::gather_locals::DeclOrigin;
|
||||
use crate::{FnCtxt, LoweredTy, errors};
|
||||
|
||||
|
@ -270,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
PatKind::Wild | PatKind::Err(_) => expected,
|
||||
// We allow any type here; we ensure that the type is uninhabited during match checking.
|
||||
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::Binding(ba, var_id, ident, sub) => {
|
||||
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)
|
||||
}
|
||||
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) => {
|
||||
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" {}`.
|
||||
//
|
||||
// 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,
|
||||
_ => AdjustMode::Peel,
|
||||
},
|
||||
|
@ -493,10 +494,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
(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(
|
||||
&self,
|
||||
span: Span,
|
||||
lt: &hir::Expr<'tcx>,
|
||||
lt: &hir::PatExpr<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
ti: &TopInfo<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
|
@ -507,7 +526,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Byte string patterns behave the same way as array patterns
|
||||
// They can denote both statically and dynamically-sized byte arrays.
|
||||
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);
|
||||
if let ty::Ref(_, inner_ty, _) = *expected.kind()
|
||||
&& 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()
|
||||
&& 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 expected = self.resolve_vars_if_possible(expected);
|
||||
|
@ -565,15 +589,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn check_pat_range(
|
||||
&self,
|
||||
span: Span,
|
||||
lhs: Option<&'tcx hir::Expr<'tcx>>,
|
||||
rhs: Option<&'tcx hir::Expr<'tcx>>,
|
||||
lhs: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
rhs: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
expected: Ty<'tcx>,
|
||||
ti: &TopInfo<'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,
|
||||
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.
|
||||
// The early check here is not for correctness, but rather better
|
||||
// diagnostics (e.g. when `&str` is being matched, `expected` will
|
||||
|
@ -919,7 +943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| PatKind::Box(..)
|
||||
| PatKind::Deref(_)
|
||||
| PatKind::Ref(..)
|
||||
| PatKind::Lit(..)
|
||||
| PatKind::Expr(..)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Err(_) => break 'block None,
|
||||
},
|
||||
|
@ -1053,7 +1077,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
fn check_pat_path(
|
||||
&self,
|
||||
pat: &Pat<'tcx>,
|
||||
hir_id: HirId,
|
||||
span: Span,
|
||||
qpath: &hir::QPath<'_>,
|
||||
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
|
||||
expected: Ty<'tcx>,
|
||||
|
@ -1072,8 +1097,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
|
||||
let expected = "unit struct, unit variant or constant";
|
||||
let e =
|
||||
report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0533, expected);
|
||||
let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
|
||||
return Ty::new_error(tcx, e);
|
||||
}
|
||||
Res::SelfCtor(def_id) => {
|
||||
|
@ -1088,7 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
res,
|
||||
None,
|
||||
qpath,
|
||||
pat.span,
|
||||
span,
|
||||
E0533,
|
||||
"unit struct",
|
||||
);
|
||||
|
@ -1107,11 +1131,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Type-check the path.
|
||||
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) =
|
||||
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
|
||||
}
|
||||
|
@ -1154,13 +1178,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn emit_bad_pat_path(
|
||||
&self,
|
||||
mut e: Diag<'_>,
|
||||
pat: &hir::Pat<'tcx>,
|
||||
hir_id: HirId,
|
||||
pat_span: Span,
|
||||
res: Res,
|
||||
pat_res: Res,
|
||||
pat_ty: Ty<'tcx>,
|
||||
segments: &'tcx [hir::PathSegment<'tcx>],
|
||||
) {
|
||||
let pat_span = pat.span;
|
||||
if let Some(span) = self.tcx.hir().res_span(pat_res) {
|
||||
e.span_label(span, format!("{} defined here", res.descr()));
|
||||
if let [hir::PathSegment { ident, .. }] = &*segments {
|
||||
|
@ -1173,7 +1197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
res.descr(),
|
||||
),
|
||||
);
|
||||
match self.tcx.parent_hir_node(pat.hir_id) {
|
||||
match self.tcx.parent_hir_node(hir_id) {
|
||||
hir::Node::PatField(..) => {
|
||||
e.span_suggestion_verbose(
|
||||
ident.span.shrink_to_hi(),
|
||||
|
@ -1813,9 +1837,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
} else if inexistent_fields.len() == 1 {
|
||||
match pat_field.pat.kind {
|
||||
PatKind::Lit(expr)
|
||||
PatKind::Expr(_)
|
||||
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),
|
||||
) => {}
|
||||
_ => {
|
||||
|
|
|
@ -147,15 +147,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
|
|||
self.visit_body(body);
|
||||
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);
|
||||
}
|
||||
|
||||
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> {
|
||||
|
|
|
@ -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(..) => {
|
||||
self.visit_field_id(e.hir_id);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(anon_const) => {
|
||||
self.visit_node_id(e.span, anon_const.hir_id);
|
||||
|
||||
let body = self.tcx().hir().body(anon_const.body);
|
||||
self.visit_body(body);
|
||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||
self.visit_const_block(e.span, anon_const);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -335,6 +339,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
|||
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>) {
|
||||
intravisit::walk_local(self, l);
|
||||
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.
|
||||
Paren(_)
|
||||
// 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.
|
||||
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
||||
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::Pat(pat) => pat.span,
|
||||
Node::PatField(field) => field.span,
|
||||
Node::PatExpr(lit) => lit.span,
|
||||
Node::Arm(arm) => arm.span,
|
||||
Node::Block(block) => block.span,
|
||||
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::Pat(_) => node_str("pat"),
|
||||
Node::PatField(_) => node_str("pattern field"),
|
||||
Node::PatExpr(_) => node_str("pattern literal"),
|
||||
Node::Param(_) => node_str("param"),
|
||||
Node::Arm(_) => node_str("arm"),
|
||||
Node::Block(_) => node_str("block"),
|
||||
|
|
|
@ -154,7 +154,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
|
||||
fn lower_pattern_range_endpoint(
|
||||
&mut self,
|
||||
expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
) -> Result<
|
||||
(Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
|
||||
ErrorGuaranteed,
|
||||
|
@ -200,13 +200,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
/// This is only called when the range is already known to be malformed.
|
||||
fn error_on_literal_overflow(
|
||||
&self,
|
||||
expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
use hir::{ExprKind, UnOp};
|
||||
use rustc_ast::ast::LitKind;
|
||||
|
||||
let Some(mut expr) = expr else {
|
||||
let Some(expr) = expr else {
|
||||
return Ok(());
|
||||
};
|
||||
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
|
||||
// `eval_bits`, an overflowed value has already been wrapped around.
|
||||
// We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint.
|
||||
let mut negated = false;
|
||||
if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind {
|
||||
negated = true;
|
||||
expr = sub_expr;
|
||||
}
|
||||
let ExprKind::Lit(lit) = expr.kind else {
|
||||
let hir::PatExprKind::Lit { lit, negated } = expr.kind else {
|
||||
return Ok(());
|
||||
};
|
||||
let LitKind::Int(lit_val, _) = lit.node else {
|
||||
|
@ -248,8 +242,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
|
||||
fn lower_pattern_range(
|
||||
&mut self,
|
||||
lo_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
hi_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
lo_expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
hi_expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
end: RangeEnd,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
|
@ -330,7 +324,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
|
||||
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) => {
|
||||
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`
|
||||
/// which would overflow if we tried to evaluate `128_i8` and then negate
|
||||
/// afterwards.
|
||||
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
|
||||
let (lit, neg) = match expr.kind {
|
||||
hir::ExprKind::Path(ref qpath) => {
|
||||
fn lower_lit(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> {
|
||||
let (lit, neg) = match &expr.kind {
|
||||
hir::PatExprKind::Path(qpath) => {
|
||||
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);
|
||||
}
|
||||
hir::ExprKind::Lit(ref lit) => (lit, false),
|
||||
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),
|
||||
hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
|
||||
};
|
||||
|
||||
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 };
|
||||
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,
|
||||
|
|
|
@ -656,14 +656,14 @@ impl<'a> Parser<'a> {
|
|||
fn visit_pat(&mut self, p: &'a Pat) -> Self::Result {
|
||||
match &p.kind {
|
||||
// Base expression
|
||||
PatKind::Err(_) | PatKind::Lit(_) => {
|
||||
PatKind::Err(_) | PatKind::Expr(_) => {
|
||||
self.maybe_add_suggestions_then_emit(p.span, p.span, false)
|
||||
}
|
||||
|
||||
// Sub-patterns
|
||||
// FIXME: this doesn't work with recursive subpats (`&mut &mut <err>`)
|
||||
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)
|
||||
}
|
||||
|
@ -766,7 +766,7 @@ impl<'a> Parser<'a> {
|
|||
if let Some(re) = self.parse_range_end() {
|
||||
self.parse_pat_range_begin_with(const_expr, re)?
|
||||
} else {
|
||||
PatKind::Lit(const_expr)
|
||||
PatKind::Expr(const_expr)
|
||||
}
|
||||
} else if self.is_builtin() {
|
||||
self.parse_pat_builtin()?
|
||||
|
@ -833,7 +833,7 @@ impl<'a> Parser<'a> {
|
|||
.struct_span_err(self_.token.span, msg)
|
||||
.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 {
|
||||
// Try to parse everything else as literal with optional minus
|
||||
match self.parse_literal_maybe_minus() {
|
||||
|
@ -845,7 +845,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
match self.parse_range_end() {
|
||||
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),
|
||||
|
@ -989,7 +989,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
match &pat.kind {
|
||||
// recover ranges with parentheses around the `(start)..`
|
||||
PatKind::Lit(begin)
|
||||
PatKind::Expr(begin)
|
||||
if self.may_recover()
|
||||
&& let Some(form) = self.parse_range_end() =>
|
||||
{
|
||||
|
|
|
@ -304,7 +304,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
Box,
|
||||
Deref,
|
||||
Ref,
|
||||
Lit,
|
||||
Expr,
|
||||
Guard,
|
||||
Range,
|
||||
Slice,
|
||||
|
@ -587,7 +587,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
|||
Box,
|
||||
Deref,
|
||||
Ref,
|
||||
Lit,
|
||||
Expr,
|
||||
Range,
|
||||
Slice,
|
||||
Rest,
|
||||
|
|
|
@ -1130,7 +1130,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
let None = following_seg else { return };
|
||||
for rib in self.ribs[ValueNS].iter().rev() {
|
||||
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 {
|
||||
if field.name == segment.ident.name {
|
||||
if spans.iter().all(|(_, had_error)| had_error.is_err()) {
|
||||
|
|
|
@ -1592,15 +1592,9 @@ impl Step for Extended {
|
|||
prepare("cargo");
|
||||
prepare("rust-std");
|
||||
prepare("rust-analysis");
|
||||
|
||||
for tool in &[
|
||||
"clippy",
|
||||
"rustfmt",
|
||||
"rust-analyzer",
|
||||
"rust-docs",
|
||||
"miri",
|
||||
"rustc-codegen-cranelift",
|
||||
] {
|
||||
prepare("clippy");
|
||||
prepare("rust-analyzer");
|
||||
for tool in &["rust-docs", "miri", "rustc-codegen-cranelift"] {
|
||||
if built_tools.contains(tool) {
|
||||
prepare(tool);
|
||||
}
|
||||
|
@ -1640,8 +1634,6 @@ impl Step for Extended {
|
|||
"rust-analyzer-preview".to_string()
|
||||
} else if name == "clippy" {
|
||||
"clippy-preview".to_string()
|
||||
} else if name == "rustfmt" {
|
||||
"rustfmt-preview".to_string()
|
||||
} else if name == "miri" {
|
||||
"miri-preview".to_string()
|
||||
} else if name == "rustc-codegen-cranelift" {
|
||||
|
@ -1661,7 +1653,7 @@ impl Step for Extended {
|
|||
prepare("cargo");
|
||||
prepare("rust-analysis");
|
||||
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) {
|
||||
prepare(tool);
|
||||
}
|
||||
|
@ -1779,24 +1771,6 @@ impl Step for Extended {
|
|||
.arg(etc.join("msi/remove-duplicates.xsl"))
|
||||
.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") {
|
||||
command(&heat)
|
||||
.current_dir(&exe)
|
||||
|
@ -1868,9 +1842,6 @@ impl Step for Extended {
|
|||
if built_tools.contains("clippy") {
|
||||
cmd.arg("-dClippyDir=clippy");
|
||||
}
|
||||
if built_tools.contains("rustfmt") {
|
||||
cmd.arg("-dRustFmtDir=rustfmt");
|
||||
}
|
||||
if built_tools.contains("rust-docs") {
|
||||
cmd.arg("-dDocsDir=rust-docs");
|
||||
}
|
||||
|
@ -1897,9 +1868,6 @@ impl Step for Extended {
|
|||
if built_tools.contains("clippy") {
|
||||
candle("ClippyGroup.wxs".as_ref());
|
||||
}
|
||||
if built_tools.contains("rustfmt") {
|
||||
candle("RustFmtGroup.wxs".as_ref());
|
||||
}
|
||||
if built_tools.contains("miri") {
|
||||
candle("MiriGroup.wxs".as_ref());
|
||||
}
|
||||
|
@ -1938,9 +1906,6 @@ impl Step for Extended {
|
|||
if built_tools.contains("clippy") {
|
||||
cmd.arg("ClippyGroup.wixobj");
|
||||
}
|
||||
if built_tools.contains("rustfmt") {
|
||||
cmd.arg("RustFmtGroup.wixobj");
|
||||
}
|
||||
if built_tools.contains("miri") {
|
||||
cmd.arg("MiriGroup.wixobj");
|
||||
}
|
||||
|
|
|
@ -172,11 +172,6 @@
|
|||
<!-- tool-rust-docs-end -->
|
||||
<Directory Id="Cargo" 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>
|
||||
|
||||
|
@ -284,41 +279,7 @@
|
|||
<ComponentRef Id="PathEnvPerMachine" />
|
||||
<ComponentRef Id="PathEnvPerUser" />
|
||||
</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" />
|
||||
</Product>
|
||||
</Wix>
|
||||
|
|
|
@ -314,9 +314,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
|
|||
PatKind::Box(p) => return name_from_pat(p),
|
||||
PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)),
|
||||
PatKind::Ref(p, _) => return name_from_pat(p),
|
||||
PatKind::Lit(..) => {
|
||||
PatKind::Expr(..) => {
|
||||
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("()");
|
||||
}
|
||||
|
|
|
@ -3,8 +3,11 @@ use clippy_utils::numeric_literal;
|
|||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt};
|
||||
use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind, StructTailExpr};
|
||||
use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat, walk_stmt};
|
||||
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_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
|
||||
|
@ -219,6 +222,22 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
|
|||
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<'_>) {
|
||||
match stmt.kind {
|
||||
// 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::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::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::{
|
||||
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
|
||||
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath,
|
||||
TraitItemRef, TyKind,
|
||||
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy,
|
||||
QPath, TraitItemRef, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
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
|
||||
&& match lt.pat.kind {
|
||||
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,
|
||||
}
|
||||
&& !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::ast::RangeLimits;
|
||||
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_middle::ty;
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
|||
{
|
||||
let arg = peel_ref_operators(cx, arg);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
&& 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) {
|
||||
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
|
||||
(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,
|
||||
_ => CharRange::Otherwise,
|
||||
}
|
||||
} else {
|
||||
CharRange::Otherwise
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt;
|
|||
use rustc_ast::LitKind;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
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_middle::lint::in_external_macro;
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
@ -38,14 +38,13 @@ declare_clippy_lint! {
|
|||
}
|
||||
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
|
||||
|
||||
fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> {
|
||||
if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind {
|
||||
expr_as_i128(expr).map(|num| -num)
|
||||
} else if let ExprKind::Lit(lit) = expr.kind
|
||||
fn expr_as_i128(expr: &PatExpr<'_>) -> Option<i128> {
|
||||
if let PatExprKind::Lit { lit, negated } = expr.kind
|
||||
&& let LitKind::Int(num, _) = lit.node
|
||||
{
|
||||
// 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 {
|
||||
None
|
||||
}
|
||||
|
@ -58,7 +57,7 @@ struct Num {
|
|||
}
|
||||
|
||||
impl Num {
|
||||
fn new(expr: &Expr<'_>) -> Option<Self> {
|
||||
fn new(expr: &PatExpr<'_>) -> Option<Self> {
|
||||
Some(Self {
|
||||
val: expr_as_i128(expr)?,
|
||||
span: expr.span,
|
||||
|
@ -90,7 +89,7 @@ impl LateLintPass<'_> for ManualRangePatterns {
|
|||
let mut ranges_found = Vec::new();
|
||||
|
||||
for pat in pats {
|
||||
if let PatKind::Lit(lit) = pat.kind
|
||||
if let PatKind::Expr(lit) = pat.kind
|
||||
&& let Some(num) = Num::new(lit)
|
||||
{
|
||||
numbers_found.insert(num.val);
|
||||
|
|
|
@ -4,7 +4,7 @@ use clippy_utils::source::{expr_block, snippet};
|
|||
use clippy_utils::sugg::Sugg;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, PatKind};
|
||||
use rustc_hir::{Arm, Expr, PatExprKind, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
|
||||
|
@ -21,8 +21,8 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
|
|||
move |diag| {
|
||||
if arms.len() == 2 {
|
||||
// no guards
|
||||
let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
|
||||
if let ExprKind::Lit(lit) = arm_bool.kind {
|
||||
let exprs = if let PatKind::Expr(arm_bool) = arms[0].pat.kind {
|
||||
if let PatExprKind::Lit { lit, .. } = arm_bool.kind {
|
||||
match lit.node {
|
||||
LitKind::Bool(true) => Some((arms[0].body, arms[1].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_errors::Applicability;
|
||||
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::{LateContext, LintContext};
|
||||
use rustc_middle::ty;
|
||||
|
@ -311,9 +311,9 @@ impl<'a> NormalizedPat<'a> {
|
|||
);
|
||||
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.
|
||||
ExprKind::Lit(lit) => match lit.node {
|
||||
PatExprKind::Lit { lit, negated: false } => match lit.node {
|
||||
LitKind::Str(sym, _) => Self::LitStr(sym),
|
||||
LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
|
||||
LitKind::Byte(val) => Self::LitInt(val.into()),
|
||||
|
@ -330,7 +330,7 @@ impl<'a> NormalizedPat<'a> {
|
|||
let start = match start {
|
||||
None => 0,
|
||||
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::Char(val) => val.into(),
|
||||
LitKind::Byte(val) => val.into(),
|
||||
|
@ -342,7 +342,7 @@ impl<'a> NormalizedPat<'a> {
|
|||
let (end, bounds) = match end {
|
||||
None => (u128::MAX, RangeEnd::Included),
|
||||
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::Char(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_errors::Applicability;
|
||||
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_middle::ty;
|
||||
use rustc_span::Span;
|
||||
|
@ -85,8 +85,8 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
|
|||
};
|
||||
|
||||
for arm in arms {
|
||||
if let PatKind::Lit(Expr {
|
||||
kind: ExprKind::Lit(lit),
|
||||
if let PatKind::Expr(PatExpr {
|
||||
kind: PatExprKind::Lit { lit, negated: false },
|
||||
..
|
||||
}) = arm.pat.kind
|
||||
&& let LitKind::Str(symbol, _) = lit.node
|
||||
|
|
|
@ -8,7 +8,7 @@ use clippy_utils::{
|
|||
};
|
||||
use rustc_errors::Applicability;
|
||||
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_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`
|
||||
Node::Item(item) => {
|
||||
if let ItemKind::Fn{ .. } = item.kind {
|
||||
if let ItemKind::Fn { .. } = item.kind {
|
||||
let output = cx
|
||||
.tcx
|
||||
.fn_sig(item.owner_id)
|
||||
|
@ -189,8 +189,12 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
|
|||
});
|
||||
},
|
||||
// Example: `5 => 5`
|
||||
(PatKind::Lit(pat_lit_expr), ExprKind::Lit(expr_spanned)) => {
|
||||
if let ExprKind::Lit(pat_spanned) = &pat_lit_expr.kind {
|
||||
(PatKind::Expr(pat_expr_expr), ExprKind::Lit(expr_spanned)) => {
|
||||
if let PatExprKind::Lit {
|
||||
lit: pat_spanned,
|
||||
negated: false,
|
||||
} = &pat_expr_expr.kind
|
||||
{
|
||||
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 PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
|
||||
let lhs_const = if let Some(lhs) = lhs {
|
||||
ConstEvalCtxt::new(cx).eval(lhs)?
|
||||
ConstEvalCtxt::new(cx).eval_pat_expr(lhs)?
|
||||
} else {
|
||||
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))?
|
||||
};
|
||||
let rhs_const = if let Some(rhs) = rhs {
|
||||
ConstEvalCtxt::new(cx).eval(rhs)?
|
||||
ConstEvalCtxt::new(cx).eval_pat_expr(rhs)?
|
||||
} else {
|
||||
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))?
|
||||
|
@ -57,8 +57,10 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
|||
});
|
||||
}
|
||||
|
||||
if let PatKind::Lit(value) = pat.kind {
|
||||
let value = ConstEvalCtxt::new(cx).eval_full_int(value)?;
|
||||
if let PatKind::Expr(value) = pat.kind {
|
||||
let value = ConstEvalCtxt::new(cx)
|
||||
.eval_pat_expr(value)?
|
||||
.int_value(cx.tcx, cx.typeck_results().node_type(pat.hir_id))?;
|
||||
return Some(SpannedRange {
|
||||
span: pat.span,
|
||||
node: (value, EndBound::Included(value)),
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
|
||||
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_middle::ty::{self, GenericArgKind, Ty};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
@ -74,8 +74,8 @@ fn find_match_true<'tcx>(
|
|||
span: Span,
|
||||
message: &'static str,
|
||||
) {
|
||||
if let PatKind::Lit(lit) = pat.kind
|
||||
&& let ExprKind::Lit(lit) = lit.kind
|
||||
if let PatKind::Expr(lit) = pat.kind
|
||||
&& let PatExprKind::Lit { lit, negated: false } = lit.kind
|
||||
&& let LitKind::Bool(pat_is_true) = lit.node
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_arena::DroplessArena;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
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_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef};
|
||||
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 (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 Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_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.
|
||||
let pat_ref_count = match pat.kind {
|
||||
// string literals are already a reference.
|
||||
PatKind::Lit(Expr {
|
||||
kind: ExprKind::Lit(lit),
|
||||
PatKind::Expr(PatExpr {
|
||||
kind: PatExprKind::Lit { lit, negated: false },
|
||||
..
|
||||
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
|
||||
_ => pat_ref_count,
|
||||
|
@ -384,7 +384,7 @@ impl<'a> PatState<'a> {
|
|||
|
||||
PatKind::Wild
|
||||
| PatKind::Binding(_, _, _, None)
|
||||
| PatKind::Lit(_)
|
||||
| PatKind::Expr(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Path(_)
|
||||
| PatKind::Never
|
||||
|
|
|
@ -11,7 +11,7 @@ use clippy_utils::visitors::{Descend, for_each_expr};
|
|||
use itertools::Itertools;
|
||||
use rustc_ast::{BinOpKind, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind};
|
||||
use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
|
|||
return ControlFlow::Break(());
|
||||
}
|
||||
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 {
|
||||
set_char_spans.push(lit.span);
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ impl EarlyLintPass for UnnestedOrPatterns {
|
|||
}
|
||||
|
||||
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.
|
||||
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`,
|
||||
// with which a pattern `C(p_0)` may be formed,
|
||||
// which we would want to join with other `C(p_j)`s.
|
||||
Ident(.., None) | Lit(_) | Wild | 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,
|
||||
// and almost always requires adding parens (increasing noisiness).
|
||||
// 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_hir::{
|
||||
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_session::declare_lint_pass;
|
||||
|
@ -643,6 +643,27 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
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<'_>>) {
|
||||
let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind");
|
||||
macro_rules! kind {
|
||||
|
@ -717,17 +738,17 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
kind!("Guard({pat}, {cond})");
|
||||
self.pat(pat);
|
||||
self.expr(cond);
|
||||
}
|
||||
PatKind::Lit(lit_expr) => {
|
||||
},
|
||||
PatKind::Expr(lit_expr) => {
|
||||
bind!(self, lit_expr);
|
||||
kind!("Lit({lit_expr})");
|
||||
self.expr(lit_expr);
|
||||
kind!("Expr({lit_expr})");
|
||||
self.pat_expr(lit_expr);
|
||||
},
|
||||
PatKind::Range(start, end, end_kind) => {
|
||||
opt_bind!(self, start, end);
|
||||
kind!("Range({start}, {end}, RangeEnd::{end_kind:?})");
|
||||
start.if_some(|e| self.expr(e));
|
||||
end.if_some(|e| self.expr(e));
|
||||
start.if_some(|e| self.pat_expr(e));
|
||||
end.if_some(|e| self.pat_expr(e));
|
||||
},
|
||||
PatKind::Slice(start, middle, 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(r)) => eq_pat(l, r),
|
||||
(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)) => {
|
||||
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.
|
||||
#![allow(clippy::float_cmp)]
|
||||
|
||||
use crate::macros::HirNode;
|
||||
use crate::source::{SpanRangeExt, walk_span_to_context};
|
||||
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_data_structures::sync::Lrc;
|
||||
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_lint::LateContext;
|
||||
use rustc_middle::mir::ConstValue;
|
||||
|
@ -442,18 +441,29 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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) => {
|
||||
let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() {
|
||||
pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option<Constant<'tcx>> {
|
||||
match &pat_expr.kind {
|
||||
PatExprKind::Lit { lit, negated } => {
|
||||
let ty = self.typeck.node_type_opt(pat_expr.hir_id);
|
||||
let val = lit_to_mir_constant(&lit.node, ty);
|
||||
if *negated {
|
||||
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
|
||||
} else {
|
||||
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)?;
|
||||
// If source is already Constant we wouldn't want to override it with CoreConstant
|
||||
self_.source.set(
|
||||
|
@ -465,7 +475,14 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
|
|||
);
|
||||
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::Lit(lit) => {
|
||||
if is_direct_expn_of(e.span, "cfg").is_some() {
|
||||
|
|
|
@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res};
|
|||
use rustc_hir::{
|
||||
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
|
||||
ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
|
||||
Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty,
|
||||
TyKind,
|
||||
Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
|
||||
TraitBoundModifiers, Ty, TyKind,
|
||||
};
|
||||
use rustc_lexer::{TokenKind, tokenize};
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -489,6 +489,24 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
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.
|
||||
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
|
||||
match (&left.kind, &right.kind) {
|
||||
|
@ -507,11 +525,11 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
eq
|
||||
},
|
||||
(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::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(le.as_ref(), re.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_pat_expr(a, b))
|
||||
&& (li == ri)
|
||||
},
|
||||
(&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);
|
||||
}
|
||||
|
||||
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<'_>) {
|
||||
std::mem::discriminant(&pat.kind).hash(&mut self.s);
|
||||
match pat.kind {
|
||||
|
@ -1084,7 +1114,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
}
|
||||
},
|
||||
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) => {
|
||||
for pat in pats {
|
||||
self.hash_pat(pat);
|
||||
|
@ -1093,10 +1123,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
PatKind::Path(ref qpath) => self.hash_qpath(qpath),
|
||||
PatKind::Range(s, e, i) => {
|
||||
if let Some(s) = s {
|
||||
self.hash_expr(s);
|
||||
self.hash_pat_expr(s);
|
||||
}
|
||||
if let Some(e) = e {
|
||||
self.hash_expr(e);
|
||||
self.hash_pat_expr(e);
|
||||
}
|
||||
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
|
||||
&& let ExprKind::Let(let_expr) = cond.kind
|
||||
&& let PatKind::Lit(lit_expr) = let_expr.pat.kind
|
||||
&& let ExprKind::Lit(ref lit) = lit_expr.kind
|
||||
&& let PatKind::Expr(lit_expr) = let_expr.pat.kind
|
||||
&& let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
|
||||
&& let LitKind::Bool(true) = lit.node
|
||||
&& let ExprKind::Path(ref qpath) = let_expr.init.kind
|
||||
&& match_qpath(qpath, &["a"])
|
||||
|
|
|
@ -76,8 +76,8 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While:
|
|||
// 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)
|
||||
&& let PatKind::Lit(lit_expr) = let_pat.kind
|
||||
&& let ExprKind::Lit(ref lit) = lit_expr.kind
|
||||
&& let PatKind::Expr(lit_expr) = let_pat.kind
|
||||
&& let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
|
||||
&& let LitKind::Bool(true) = lit.node
|
||||
&& let ExprKind::Path(ref qpath) = let_expr.kind
|
||||
&& match_qpath(qpath, &["a"])
|
||||
|
|
|
@ -4,14 +4,14 @@ if let StmtKind::Let(local) = stmt.kind
|
|||
&& let ExprKind::Lit(ref lit) = scrutinee.kind
|
||||
&& let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
|
||||
&& arms.len() == 3
|
||||
&& let PatKind::Lit(lit_expr) = arms[0].pat.kind
|
||||
&& let ExprKind::Lit(ref lit1) = lit_expr.kind
|
||||
&& let PatKind::Expr(lit_expr) = arms[0].pat.kind
|
||||
&& let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind
|
||||
&& let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node
|
||||
&& arms[0].guard.is_none()
|
||||
&& let ExprKind::Lit(ref lit2) = arms[0].body.kind
|
||||
&& let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
|
||||
&& let PatKind::Lit(lit_expr1) = arms[1].pat.kind
|
||||
&& let ExprKind::Lit(ref lit3) = lit_expr1.kind
|
||||
&& let PatKind::Expr(lit_expr1) = arms[1].pat.kind
|
||||
&& let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind
|
||||
&& let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node
|
||||
&& arms[1].guard.is_none()
|
||||
&& 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"])
|
||||
&& fields.len() == 1
|
||||
&& fields[0].ident.as_str() == "field"
|
||||
&& let PatKind::Lit(lit_expr) = fields[0].pat.kind
|
||||
&& let ExprKind::Lit(ref lit) = lit_expr.kind
|
||||
&& let PatKind::Expr(lit_expr) = fields[0].pat.kind
|
||||
&& let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
|
||||
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
|
||||
&& arm.guard.is_none()
|
||||
&& 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
|
||||
&& match_qpath(qpath, &["TestTuple"])
|
||||
&& fields.len() == 1
|
||||
&& let PatKind::Lit(lit_expr) = fields[0].kind
|
||||
&& let ExprKind::Lit(ref lit) = lit_expr.kind
|
||||
&& let PatKind::Expr(lit_expr) = fields[0].kind
|
||||
&& let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
|
||||
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
|
||||
&& arm.guard.is_none()
|
||||
&& 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::Wild
|
||||
| ast::PatKind::Err(_)
|
||||
| ast::PatKind::Lit(_) => true,
|
||||
| ast::PatKind::Expr(_) => true,
|
||||
ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
|
||||
ast::PatKind::Struct(..)
|
||||
| ast::PatKind::MacCall(..)
|
||||
|
@ -293,7 +293,7 @@ impl Rewrite for Pat {
|
|||
let path_str = rewrite_path(context, PathContext::Expr, q_self, path, 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)
|
||||
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) => {
|
||||
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,
|
||||
},
|
||||
TuplePatField::Dotdot(..) => false,
|
||||
|
|
|
@ -569,7 +569,7 @@ fn test_pat() {
|
|||
c1!(pat, [ &pat ], "&pat");
|
||||
c1!(pat, [ &mut pat ], "&mut pat");
|
||||
|
||||
// PatKind::Lit
|
||||
// PatKind::Expr
|
||||
c1!(pat, [ 1_000_i8 ], "1_000_i8");
|
||||
|
||||
// PatKind::Range
|
||||
|
|
|
@ -6,7 +6,7 @@ macro_rules! enum_number {
|
|||
|
||||
fn foo(value: i32) -> Option<$name> {
|
||||
match value {
|
||||
$( $value => Some($name::$variant), )* // PatKind::Lit
|
||||
$( $value => Some($name::$variant), )* // PatKind::Expr
|
||||
$( $value ..= 42 => Some($name::$variant), )* // PatKind::Range
|
||||
_ => 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>,
|
||||
}
|
||||
|
||||
enum Foo {
|
||||
Bar { a: i32 },
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let website = Website {
|
||||
url: "http://www.example.com".into(),
|
||||
|
@ -18,4 +22,9 @@ fn main() {
|
|||
println!("[{}]({})", title, url); //~ ERROR cannot find value `title` 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 `,`
|
||||
--> $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 {
|
||||
| ------- ^
|
||||
|
@ -7,13 +7,21 @@ LL | if let Website { url, Some(title) } = website {
|
|||
| while parsing the fields for this pattern
|
||||
|
||||
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 {
|
||||
| ------------------- this pattern doesn't include `title`, which is available in `Website`
|
||||
LL | println!("[{}]({})", title, url);
|
||||
| ^^^^^ 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`.
|
||||
|
|
|
@ -651,8 +651,8 @@ mod patterns {
|
|||
let &mut pat;
|
||||
}
|
||||
|
||||
/// PatKind::Lit
|
||||
fn pat_lit() {
|
||||
/// PatKind::Expr
|
||||
fn pat_expr() {
|
||||
let 1_000_i8;
|
||||
let -"";
|
||||
}
|
||||
|
|
|
@ -567,8 +567,8 @@ mod patterns {
|
|||
fn pat_deref() { let deref!(pat); }
|
||||
/// PatKind::Ref
|
||||
fn pat_ref() { let &pat; let &mut pat; }
|
||||
/// PatKind::Lit
|
||||
fn pat_lit() { let 1_000_i8; let -""; }
|
||||
/// PatKind::Expr
|
||||
fn pat_expr() { let 1_000_i8; let -""; }
|
||||
/// PatKind::Range
|
||||
fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; }
|
||||
/// PatKind::Slice
|
||||
|
|
|
@ -14,4 +14,4 @@ extern crate std;
|
|||
|
||||
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"]
|
||||
trigger_files = [
|
||||
"src/bootstrap/src/core/build_steps/test.rs",
|
||||
"src/ci",
|
||||
"src/tools/compiletest",
|
||||
"src/tools/cargotest",
|
||||
"src/tools/tidy",
|
||||
"src/tools/compiletest",
|
||||
"src/tools/miropt-test-tools",
|
||||
"src/tools/remote-test-server",
|
||||
"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"]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue