1
Fork 0

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:
bors 2025-01-08 21:31:51 +00:00
commit e26ff2f908
82 changed files with 759 additions and 506 deletions

View file

@ -37,7 +37,7 @@ Libraries
- [Move `<float>::copysign`, `<float>::abs`, `<float>::signum` to `core`](https://github.com/rust-lang/rust/pull/131304) - [Move `<float>::copysign`, `<float>::abs`, `<float>::signum` to `core`](https://github.com/rust-lang/rust/pull/131304)
- [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377) - [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377)
- [Implement `FromStr` for `CString` and `TryFrom<CString>` for `String`](https://github.com/rust-lang/rust/pull/130608) - [Implement `FromStr` for `CString` and `TryFrom<CString>` for `String`](https://github.com/rust-lang/rust/pull/130608)
- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/130635) - [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/123723)
<a id="1.84.0-Stabilized-APIs"></a> <a id="1.84.0-Stabilized-APIs"></a>

View file

@ -623,7 +623,7 @@ impl Pat {
PatKind::Wild PatKind::Wild
| PatKind::Rest | PatKind::Rest
| PatKind::Never | PatKind::Never
| PatKind::Lit(_) | PatKind::Expr(_)
| PatKind::Range(..) | PatKind::Range(..)
| PatKind::Ident(..) | PatKind::Ident(..)
| PatKind::Path(..) | PatKind::Path(..)
@ -801,8 +801,8 @@ pub enum PatKind {
/// A reference pattern (e.g., `&mut (a, b)`). /// A reference pattern (e.g., `&mut (a, b)`).
Ref(P<Pat>, Mutability), Ref(P<Pat>, Mutability),
/// A literal. /// A literal, const block or path.
Lit(P<Expr>), Expr(P<Expr>),
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>), Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>),

View file

@ -1512,7 +1512,7 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
vis.visit_ident(ident); vis.visit_ident(ident);
visit_opt(sub, |sub| vis.visit_pat(sub)); visit_opt(sub, |sub| vis.visit_pat(sub));
} }
PatKind::Lit(e) => vis.visit_expr(e), PatKind::Expr(e) => vis.visit_expr(e),
PatKind::TupleStruct(qself, path, elems) => { PatKind::TupleStruct(qself, path, elems) => {
vis.visit_qself(qself); vis.visit_qself(qself);
vis.visit_path(path); vis.visit_path(path);

View file

@ -680,7 +680,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ident(ident));
visit_opt!(visitor, visit_pat, optional_subpattern); visit_opt!(visitor, visit_pat, optional_subpattern);
} }
PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)), PatKind::Expr(expression) => try_visit!(visitor.visit_expr(expression)),
PatKind::Range(lower_bound, upper_bound, _end) => { PatKind::Range(lower_bound, upper_bound, _end) => {
visit_opt!(visitor, visit_expr, lower_bound); visit_opt!(visitor, visit_expr, lower_bound);
visit_opt!(visitor, visit_expr, upper_bound); visit_opt!(visitor, visit_expr, upper_bound);

View file

@ -102,17 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let kind = match &e.kind { let kind = match &e.kind {
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(c) => { ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),
let c = self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
hir::ConstBlock {
def_id,
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
}
});
hir::ExprKind::ConstBlock(c)
}
ExprKind::Repeat(expr, count) => { ExprKind::Repeat(expr, count) => {
let expr = self.lower_expr(expr); let expr = self.lower_expr(expr);
let count = self.lower_array_length_to_const_arg(count); let count = self.lower_array_length_to_const_arg(count);
@ -153,18 +143,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let ohs = self.lower_expr(ohs); let ohs = self.lower_expr(ohs);
hir::ExprKind::Unary(op, ohs) hir::ExprKind::Unary(op, ohs)
} }
ExprKind::Lit(token_lit) => { ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),
let lit_kind = match LitKind::from_token_lit(*token_lit) {
Ok(lit_kind) => lit_kind,
Err(err) => {
let guar =
report_lit_error(&self.tcx.sess.psess, err, *token_lit, e.span);
LitKind::Err(guar)
}
};
let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind));
hir::ExprKind::Lit(lit)
}
ExprKind::IncludedBytes(bytes) => { ExprKind::IncludedBytes(bytes) => {
let lit = self.arena.alloc(respan( let lit = self.arena.alloc(respan(
self.lower_span(e.span), self.lower_span(e.span),
@ -403,6 +382,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
}) })
} }
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
hir::ConstBlock {
def_id,
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
}
})
}
pub(crate) fn lower_lit(
&mut self,
token_lit: &token::Lit,
span: Span,
) -> &'hir Spanned<LitKind> {
let lit_kind = match LitKind::from_token_lit(*token_lit) {
Ok(lit_kind) => lit_kind,
Err(err) => {
let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);
LitKind::Err(guar)
}
};
self.arena.alloc(respan(self.lower_span(span), lit_kind))
}
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
match u { match u {
UnOp::Deref => hir::UnOp::Deref, UnOp::Deref => hir::UnOp::Deref,

View file

@ -209,6 +209,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
}); });
} }
fn visit_pat_expr(&mut self, expr: &'hir PatExpr<'hir>) {
self.insert(expr.span, expr.hir_id, Node::PatExpr(expr));
self.with_parent(expr.hir_id, |this| {
intravisit::walk_pat_expr(this, expr);
});
}
fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) { fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) {
self.insert(field.span, field.hir_id, Node::PatField(field)); self.insert(field.span, field.hir_id, Node::PatField(field));
self.with_parent(field.hir_id, |this| { self.with_parent(field.hir_id, |this| {

View file

@ -35,6 +35,7 @@
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]
#![warn(unreachable_pub)] #![warn(unreachable_pub)]

View file

@ -1,9 +1,12 @@
use std::sync::Arc;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::*; use rustc_ast::*;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_span::source_map::Spanned; use rustc_middle::span_bug;
use rustc_span::source_map::{Spanned, respan};
use rustc_span::{Ident, Span}; use rustc_span::{Ident, Span};
use super::errors::{ use super::errors::{
@ -35,8 +38,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lower_sub, lower_sub,
); );
} }
PatKind::Lit(e) => { PatKind::Expr(e) => {
break hir::PatKind::Lit(self.lower_expr_within_pat(e, false)); break hir::PatKind::Expr(self.lower_expr_within_pat(e, false));
} }
PatKind::TupleStruct(qself, path, pats) => { PatKind::TupleStruct(qself, path, pats) => {
let qpath = self.lower_qpath( let qpath = self.lower_qpath(
@ -367,24 +370,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// } // }
// m!(S); // m!(S);
// ``` // ```
fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> { fn lower_expr_within_pat(
match &expr.kind { &mut self,
ExprKind::Lit(..) expr: &Expr,
| ExprKind::ConstBlock(..) allow_paths: bool,
| ExprKind::IncludedBytes(..) ) -> &'hir hir::PatExpr<'hir> {
| ExprKind::Err(_) let err = |guar| hir::PatExprKind::Lit {
| ExprKind::Dummy => {} lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))),
ExprKind::Path(..) if allow_paths => {} negated: false,
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} };
let kind = match &expr.kind {
ExprKind::Lit(lit) => {
hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false }
}
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit {
lit: self.arena.alloc(respan(
self.lower_span(expr.span),
LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked),
)),
negated: false,
},
ExprKind::Err(guar) => err(*guar),
ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"),
ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath(
expr.id,
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
)),
ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => {
hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true }
}
_ => { _ => {
let pattern_from_macro = expr.is_approximately_pattern(); let pattern_from_macro = expr.is_approximately_pattern();
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern { let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
span: expr.span, span: expr.span,
pattern_from_macro_note: pattern_from_macro, pattern_from_macro_note: pattern_from_macro,
}); });
return self.arena.alloc(self.expr_err(expr.span, guar)); err(guar)
} }
} };
self.lower_expr(expr) self.arena.alloc(hir::PatExpr {
hir_id: self.lower_node_id(expr.id),
span: expr.span,
kind,
})
} }
} }

View file

@ -1701,7 +1701,7 @@ impl<'a> State<'a> {
self.print_pat(inner); self.print_pat(inner);
} }
} }
PatKind::Lit(e) => self.print_expr(e, FixupContext::default()), PatKind::Expr(e) => self.print_expr(e, FixupContext::default()),
PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => { PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
if let Some(e) = begin { if let Some(e) = begin {
self.print_expr(e, FixupContext::default()); self.print_expr(e, FixupContext::default());

View file

@ -11,8 +11,8 @@ pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_a
pub use super::place_ext::PlaceExt; pub use super::place_ext::PlaceExt;
pub use super::places_conflict::{PlaceConflictBias, places_conflict}; pub use super::places_conflict::{PlaceConflictBias, places_conflict};
pub use super::polonius::legacy::{ pub use super::polonius::legacy::{
AllFacts as PoloniusInput, LocationTable, PoloniusOutput, PoloniusRegionVid, RichLocation, PoloniusFacts as PoloniusInput, PoloniusLocationTable, PoloniusOutput, PoloniusRegionVid,
RustcFacts, RichLocation, RustcFacts,
}; };
pub use super::region_infer::RegionInferenceContext; pub use super::region_infer::RegionInferenceContext;
@ -33,7 +33,7 @@ pub enum ConsumerOptions {
/// without significant slowdowns. /// without significant slowdowns.
/// ///
/// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext), /// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext),
/// and additionally retrieve the [`LocationTable`] and [`PoloniusInput`] that /// and additionally retrieve the [`PoloniusLocationTable`] and [`PoloniusInput`] that
/// would be given to Polonius. Critically, this does not run Polonius, which /// would be given to Polonius. Critically, this does not run Polonius, which
/// one may want to avoid due to performance issues on large bodies. /// one may want to avoid due to performance issues on large bodies.
PoloniusInputFacts, PoloniusInputFacts,
@ -71,7 +71,7 @@ pub struct BodyWithBorrowckFacts<'tcx> {
/// The table that maps Polonius points to locations in the table. /// The table that maps Polonius points to locations in the table.
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`] /// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
/// or [`ConsumerOptions::PoloniusOutputFacts`]. /// or [`ConsumerOptions::PoloniusOutputFacts`].
pub location_table: Option<LocationTable>, pub location_table: Option<PoloniusLocationTable>,
/// Polonius input facts. /// Polonius input facts.
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`] /// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
/// or [`ConsumerOptions::PoloniusOutputFacts`]. /// or [`ConsumerOptions::PoloniusOutputFacts`].

View file

@ -60,7 +60,7 @@ use crate::diagnostics::{
use crate::path_utils::*; use crate::path_utils::*;
use crate::place_ext::PlaceExt; use crate::place_ext::PlaceExt;
use crate::places_conflict::{PlaceConflictBias, places_conflict}; use crate::places_conflict::{PlaceConflictBias, places_conflict};
use crate::polonius::legacy::{LocationTable, PoloniusOutput}; use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
use crate::prefixes::PrefixSet; use crate::prefixes::PrefixSet;
use crate::region_infer::RegionInferenceContext; use crate::region_infer::RegionInferenceContext;
use crate::renumber::RegionCtxt; use crate::renumber::RegionCtxt;
@ -179,7 +179,7 @@ fn do_mir_borrowck<'tcx>(
infcx.register_predefined_opaques_for_next_solver(def); infcx.register_predefined_opaques_for_next_solver(def);
} }
let location_table = LocationTable::new(body); let location_table = PoloniusLocationTable::new(body);
let move_data = MoveData::gather_moves(body, tcx, |_| true); let move_data = MoveData::gather_moves(body, tcx, |_| true);
let promoted_move_data = promoted let promoted_move_data = promoted
@ -250,7 +250,8 @@ fn do_mir_borrowck<'tcx>(
infcx: &infcx, infcx: &infcx,
body: promoted_body, body: promoted_body,
move_data: &move_data, move_data: &move_data,
location_table: &location_table, // no need to create a real one for the promoted, it is not used // no need to create a real location table for the promoted, it is not used
location_table: &location_table,
movable_coroutine, movable_coroutine,
fn_self_span_reported: Default::default(), fn_self_span_reported: Default::default(),
locals_are_invalidated_at_exit, locals_are_invalidated_at_exit,
@ -516,7 +517,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
/// Map from MIR `Location` to `LocationIndex`; created /// Map from MIR `Location` to `LocationIndex`; created
/// when MIR borrowck begins. /// when MIR borrowck begins.
location_table: &'a LocationTable, location_table: &'a PoloniusLocationTable,
movable_coroutine: bool, movable_coroutine: bool,
/// This keeps track of whether local variables are free-ed when the function /// This keeps track of whether local variables are free-ed when the function

View file

@ -28,7 +28,9 @@ use crate::borrow_set::BorrowSet;
use crate::consumers::ConsumerOptions; use crate::consumers::ConsumerOptions;
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors}; use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
use crate::polonius::LocalizedOutlivesConstraintSet; use crate::polonius::LocalizedOutlivesConstraintSet;
use crate::polonius::legacy::{AllFacts, AllFactsExt, LocationTable, PoloniusOutput}; use crate::polonius::legacy::{
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
};
use crate::region_infer::RegionInferenceContext; use crate::region_infer::RegionInferenceContext;
use crate::type_check::{self, MirTypeckResults}; use crate::type_check::{self, MirTypeckResults};
use crate::universal_regions::UniversalRegions; use crate::universal_regions::UniversalRegions;
@ -39,7 +41,7 @@ use crate::{BorrowckInferCtxt, polonius, renumber};
pub(crate) struct NllOutput<'tcx> { pub(crate) struct NllOutput<'tcx> {
pub regioncx: RegionInferenceContext<'tcx>, pub regioncx: RegionInferenceContext<'tcx>,
pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
pub polonius_input: Option<Box<AllFacts>>, pub polonius_input: Option<Box<PoloniusFacts>>,
pub polonius_output: Option<Box<PoloniusOutput>>, pub polonius_output: Option<Box<PoloniusOutput>>,
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>, pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
pub nll_errors: RegionErrors<'tcx>, pub nll_errors: RegionErrors<'tcx>,
@ -80,7 +82,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
universal_regions: UniversalRegions<'tcx>, universal_regions: UniversalRegions<'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
promoted: &IndexSlice<Promoted, Body<'tcx>>, promoted: &IndexSlice<Promoted, Body<'tcx>>,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
borrow_set: &BorrowSet<'tcx>, borrow_set: &BorrowSet<'tcx>,
@ -91,10 +93,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|| is_polonius_legacy_enabled; || is_polonius_legacy_enabled;
let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default() let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
|| is_polonius_legacy_enabled; || is_polonius_legacy_enabled;
let mut all_facts = let mut polonius_facts =
(polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); (polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
let elements = Rc::new(DenseLocationMap::new(body)); let location_map = Rc::new(DenseLocationMap::new(body));
// Run the MIR type-checker. // Run the MIR type-checker.
let MirTypeckResults { let MirTypeckResults {
@ -109,10 +111,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
universal_regions, universal_regions,
location_table, location_table,
borrow_set, borrow_set,
&mut all_facts, &mut polonius_facts,
flow_inits, flow_inits,
move_data, move_data,
Rc::clone(&elements), Rc::clone(&location_map),
); );
// Create the region inference context, taking ownership of the // Create the region inference context, taking ownership of the
@ -122,7 +124,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
// If requested, emit legacy polonius facts. // If requested, emit legacy polonius facts.
polonius::legacy::emit_facts( polonius::legacy::emit_facts(
&mut all_facts, &mut polonius_facts,
infcx.tcx, infcx.tcx,
location_table, location_table,
body, body,
@ -137,7 +139,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
var_infos, var_infos,
constraints, constraints,
universal_region_relations, universal_region_relations,
elements, location_map,
); );
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives // If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives
@ -147,13 +149,13 @@ pub(crate) fn compute_regions<'a, 'tcx>(
}); });
// If requested: dump NLL facts, and run legacy polonius analysis. // If requested: dump NLL facts, and run legacy polonius analysis.
let polonius_output = all_facts.as_ref().and_then(|all_facts| { let polonius_output = polonius_facts.as_ref().and_then(|polonius_facts| {
if infcx.tcx.sess.opts.unstable_opts.nll_facts { if infcx.tcx.sess.opts.unstable_opts.nll_facts {
let def_id = body.source.def_id(); let def_id = body.source.def_id();
let def_path = infcx.tcx.def_path(def_id); let def_path = infcx.tcx.def_path(def_id);
let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir) let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir)
.join(def_path.to_filename_friendly_no_crate()); .join(def_path.to_filename_friendly_no_crate());
all_facts.write_to_dir(dir_path, location_table).unwrap(); polonius_facts.write_to_dir(dir_path, location_table).unwrap();
} }
if polonius_output { if polonius_output {
@ -162,7 +164,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
let algorithm = Algorithm::from_str(&algorithm).unwrap(); let algorithm = Algorithm::from_str(&algorithm).unwrap();
debug!("compute_regions: using polonius algorithm {:?}", algorithm); debug!("compute_regions: using polonius algorithm {:?}", algorithm);
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis"); let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis");
Some(Box::new(Output::compute(all_facts, algorithm, false))) Some(Box::new(Output::compute(polonius_facts, algorithm, false)))
} else { } else {
None None
} }
@ -182,7 +184,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
NllOutput { NllOutput {
regioncx, regioncx,
opaque_type_values: remapped_opaque_tys, opaque_type_values: remapped_opaque_tys,
polonius_input: all_facts.map(Box::new), polonius_input: polonius_facts.map(Box::new),
polonius_output, polonius_output,
opt_closure_req: closure_region_requirements, opt_closure_req: closure_region_requirements,
nll_errors, nll_errors,

View file

@ -4,16 +4,16 @@ use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::move_paths::{LookupResult, MoveData}; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData};
use tracing::debug; use tracing::debug;
use super::{AllFacts, LocationIndex, LocationTable}; use super::{LocationIndex, PoloniusFacts, PoloniusLocationTable};
use crate::def_use::{self, DefUse}; use crate::def_use::{self, DefUse};
use crate::universal_regions::UniversalRegions; use crate::universal_regions::UniversalRegions;
/// Emit polonius facts for variable defs, uses, drops, and path accesses. /// Emit polonius facts for variable defs, uses, drops, and path accesses.
pub(crate) fn emit_access_facts<'tcx>( pub(crate) fn emit_access_facts<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
facts: &mut AllFacts, facts: &mut PoloniusFacts,
body: &Body<'tcx>, body: &Body<'tcx>,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
universal_regions: &UniversalRegions<'tcx>, universal_regions: &UniversalRegions<'tcx>,
) { ) {
@ -31,9 +31,9 @@ pub(crate) fn emit_access_facts<'tcx>(
/// MIR visitor extracting point-wise facts about accesses. /// MIR visitor extracting point-wise facts about accesses.
struct AccessFactsExtractor<'a, 'tcx> { struct AccessFactsExtractor<'a, 'tcx> {
facts: &'a mut AllFacts, facts: &'a mut PoloniusFacts,
move_data: &'a MoveData<'tcx>, move_data: &'a MoveData<'tcx>,
location_table: &'a LocationTable, location_table: &'a PoloniusLocationTable,
} }
impl<'tcx> AccessFactsExtractor<'_, 'tcx> { impl<'tcx> AccessFactsExtractor<'_, 'tcx> {

View file

@ -4,13 +4,13 @@ use std::fs::{self, File};
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use polonius_engine::{AllFacts as PoloniusFacts, Atom, Output}; use polonius_engine::{AllFacts, Atom, Output};
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::mir::Local; use rustc_middle::mir::Local;
use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_mir_dataflow::move_paths::MovePathIndex; use rustc_mir_dataflow::move_paths::MovePathIndex;
use super::{LocationIndex, LocationTable}; use super::{LocationIndex, PoloniusLocationTable};
use crate::BorrowIndex; use crate::BorrowIndex;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -49,11 +49,11 @@ impl polonius_engine::FactTypes for RustcFacts {
type Path = MovePathIndex; type Path = MovePathIndex;
} }
pub type AllFacts = PoloniusFacts<RustcFacts>; pub type PoloniusFacts = AllFacts<RustcFacts>;
#[extension(pub(crate) trait AllFactsExt)] #[extension(pub(crate) trait PoloniusFactsExt)]
impl AllFacts { impl PoloniusFacts {
/// Returns `true` if there is a need to gather `AllFacts` given the /// Returns `true` if there is a need to gather `PoloniusFacts` given the
/// current `-Z` flags. /// current `-Z` flags.
fn enabled(tcx: TyCtxt<'_>) -> bool { fn enabled(tcx: TyCtxt<'_>) -> bool {
tcx.sess.opts.unstable_opts.nll_facts tcx.sess.opts.unstable_opts.nll_facts
@ -63,7 +63,7 @@ impl AllFacts {
fn write_to_dir( fn write_to_dir(
&self, &self,
dir: impl AsRef<Path>, dir: impl AsRef<Path>,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
let dir: &Path = dir.as_ref(); let dir: &Path = dir.as_ref();
fs::create_dir_all(dir)?; fs::create_dir_all(dir)?;
@ -119,7 +119,7 @@ impl Atom for LocationIndex {
} }
struct FactWriter<'w> { struct FactWriter<'w> {
location_table: &'w LocationTable, location_table: &'w PoloniusLocationTable,
dir: &'w Path, dir: &'w Path,
} }
@ -141,7 +141,7 @@ trait FactRow {
fn write( fn write(
&self, &self,
out: &mut dyn Write, out: &mut dyn Write,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
) -> Result<(), Box<dyn Error>>; ) -> Result<(), Box<dyn Error>>;
} }
@ -149,7 +149,7 @@ impl FactRow for PoloniusRegionVid {
fn write( fn write(
&self, &self,
out: &mut dyn Write, out: &mut dyn Write,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
write_row(out, location_table, &[self]) write_row(out, location_table, &[self])
} }
@ -163,7 +163,7 @@ where
fn write( fn write(
&self, &self,
out: &mut dyn Write, out: &mut dyn Write,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
write_row(out, location_table, &[&self.0, &self.1]) write_row(out, location_table, &[&self.0, &self.1])
} }
@ -178,7 +178,7 @@ where
fn write( fn write(
&self, &self,
out: &mut dyn Write, out: &mut dyn Write,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
write_row(out, location_table, &[&self.0, &self.1, &self.2]) write_row(out, location_table, &[&self.0, &self.1, &self.2])
} }
@ -194,7 +194,7 @@ where
fn write( fn write(
&self, &self,
out: &mut dyn Write, out: &mut dyn Write,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3]) write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
} }
@ -202,7 +202,7 @@ where
fn write_row( fn write_row(
out: &mut dyn Write, out: &mut dyn Write,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
columns: &[&dyn FactCell], columns: &[&dyn FactCell],
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
for (index, c) in columns.iter().enumerate() { for (index, c) in columns.iter().enumerate() {
@ -213,41 +213,41 @@ fn write_row(
} }
trait FactCell { trait FactCell {
fn to_string(&self, location_table: &LocationTable) -> String; fn to_string(&self, location_table: &PoloniusLocationTable) -> String;
} }
impl FactCell for BorrowIndex { impl FactCell for BorrowIndex {
fn to_string(&self, _location_table: &LocationTable) -> String { fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
format!("{self:?}") format!("{self:?}")
} }
} }
impl FactCell for Local { impl FactCell for Local {
fn to_string(&self, _location_table: &LocationTable) -> String { fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
format!("{self:?}") format!("{self:?}")
} }
} }
impl FactCell for MovePathIndex { impl FactCell for MovePathIndex {
fn to_string(&self, _location_table: &LocationTable) -> String { fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
format!("{self:?}") format!("{self:?}")
} }
} }
impl FactCell for PoloniusRegionVid { impl FactCell for PoloniusRegionVid {
fn to_string(&self, _location_table: &LocationTable) -> String { fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
format!("{self:?}") format!("{self:?}")
} }
} }
impl FactCell for RegionVid { impl FactCell for RegionVid {
fn to_string(&self, _location_table: &LocationTable) -> String { fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
format!("{self:?}") format!("{self:?}")
} }
} }
impl FactCell for LocationIndex { impl FactCell for LocationIndex {
fn to_string(&self, location_table: &LocationTable) -> String { fn to_string(&self, location_table: &PoloniusLocationTable) -> String {
format!("{:?}", location_table.to_rich_location(*self)) format!("{:?}", location_table.to_rich_location(*self))
} }
} }

View file

@ -11,7 +11,7 @@ use rustc_middle::mir::{
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use tracing::debug; use tracing::debug;
use super::{AllFacts, LocationTable}; use super::{PoloniusFacts, PoloniusLocationTable};
use crate::borrow_set::BorrowSet; use crate::borrow_set::BorrowSet;
use crate::path_utils::*; use crate::path_utils::*;
use crate::{ use crate::{
@ -22,9 +22,9 @@ use crate::{
/// Emit `loan_invalidated_at` facts. /// Emit `loan_invalidated_at` facts.
pub(super) fn emit_loan_invalidations<'tcx>( pub(super) fn emit_loan_invalidations<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
facts: &mut AllFacts, facts: &mut PoloniusFacts,
body: &Body<'tcx>, body: &Body<'tcx>,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
borrow_set: &BorrowSet<'tcx>, borrow_set: &BorrowSet<'tcx>,
) { ) {
let dominators = body.basic_blocks.dominators(); let dominators = body.basic_blocks.dominators();
@ -35,9 +35,9 @@ pub(super) fn emit_loan_invalidations<'tcx>(
struct LoanInvalidationsGenerator<'a, 'tcx> { struct LoanInvalidationsGenerator<'a, 'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
facts: &'a mut AllFacts, facts: &'a mut PoloniusFacts,
body: &'a Body<'tcx>, body: &'a Body<'tcx>,
location_table: &'a LocationTable, location_table: &'a PoloniusLocationTable,
dominators: &'a Dominators<BasicBlock>, dominators: &'a Dominators<BasicBlock>,
borrow_set: &'a BorrowSet<'tcx>, borrow_set: &'a BorrowSet<'tcx>,
} }

View file

@ -6,16 +6,16 @@ use rustc_middle::mir::{
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use tracing::debug; use tracing::debug;
use super::{AllFacts, LocationTable}; use super::{PoloniusFacts, PoloniusLocationTable};
use crate::borrow_set::BorrowSet; use crate::borrow_set::BorrowSet;
use crate::places_conflict; use crate::places_conflict;
/// Emit `loan_killed_at` and `cfg_edge` facts at the same time. /// Emit `loan_killed_at` and `cfg_edge` facts at the same time.
pub(super) fn emit_loan_kills<'tcx>( pub(super) fn emit_loan_kills<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
facts: &mut AllFacts, facts: &mut PoloniusFacts,
body: &Body<'tcx>, body: &Body<'tcx>,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
borrow_set: &BorrowSet<'tcx>, borrow_set: &BorrowSet<'tcx>,
) { ) {
let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, facts, body }; let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, facts, body };
@ -26,8 +26,8 @@ pub(super) fn emit_loan_kills<'tcx>(
struct LoanKillsGenerator<'a, 'tcx> { struct LoanKillsGenerator<'a, 'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
facts: &'a mut AllFacts, facts: &'a mut PoloniusFacts,
location_table: &'a LocationTable, location_table: &'a PoloniusLocationTable,
borrow_set: &'a BorrowSet<'tcx>, borrow_set: &'a BorrowSet<'tcx>,
body: &'a Body<'tcx>, body: &'a Body<'tcx>,
} }

View file

@ -13,7 +13,7 @@ use tracing::debug;
/// granularity through outlives relations; however, the rich location /// granularity through outlives relations; however, the rich location
/// table serves another purpose: it compresses locations from /// table serves another purpose: it compresses locations from
/// multiple words into a single u32. /// multiple words into a single u32.
pub struct LocationTable { pub struct PoloniusLocationTable {
num_points: usize, num_points: usize,
statements_before_block: IndexVec<BasicBlock, usize>, statements_before_block: IndexVec<BasicBlock, usize>,
} }
@ -30,7 +30,7 @@ pub enum RichLocation {
Mid(Location), Mid(Location),
} }
impl LocationTable { impl PoloniusLocationTable {
pub(crate) fn new(body: &Body<'_>) -> Self { pub(crate) fn new(body: &Body<'_>) -> Self {
let mut num_points = 0; let mut num_points = 0;
let statements_before_block = body let statements_before_block = body
@ -43,8 +43,8 @@ impl LocationTable {
}) })
.collect(); .collect();
debug!("LocationTable(statements_before_block={:#?})", statements_before_block); debug!("PoloniusLocationTable(statements_before_block={:#?})", statements_before_block);
debug!("LocationTable: num_points={:#?}", num_points); debug!("PoloniusLocationTable: num_points={:#?}", num_points);
Self { num_points, statements_before_block } Self { num_points, statements_before_block }
} }

View file

@ -36,16 +36,16 @@ pub use self::facts::*;
/// ///
/// The rest of the facts are emitted during typeck and liveness. /// The rest of the facts are emitted during typeck and liveness.
pub(crate) fn emit_facts<'tcx>( pub(crate) fn emit_facts<'tcx>(
all_facts: &mut Option<AllFacts>, facts: &mut Option<PoloniusFacts>,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
body: &Body<'tcx>, body: &Body<'tcx>,
borrow_set: &BorrowSet<'tcx>, borrow_set: &BorrowSet<'tcx>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
universal_region_relations: &UniversalRegionRelations<'tcx>, universal_region_relations: &UniversalRegionRelations<'tcx>,
constraints: &MirTypeckRegionConstraints<'tcx>, constraints: &MirTypeckRegionConstraints<'tcx>,
) { ) {
let Some(facts) = all_facts else { let Some(facts) = facts else {
// We don't do anything if there are no facts to fill. // We don't do anything if there are no facts to fill.
return; return;
}; };
@ -67,9 +67,9 @@ pub(crate) fn emit_facts<'tcx>(
/// Emit facts needed for move/init analysis: moves and assignments. /// Emit facts needed for move/init analysis: moves and assignments.
fn emit_move_facts( fn emit_move_facts(
facts: &mut AllFacts, facts: &mut PoloniusFacts,
body: &Body<'_>, body: &Body<'_>,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
move_data: &MoveData<'_>, move_data: &MoveData<'_>,
) { ) {
facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l))); facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
@ -139,7 +139,7 @@ fn emit_move_facts(
/// Emit universal regions facts, and their relations. /// Emit universal regions facts, and their relations.
fn emit_universal_region_facts( fn emit_universal_region_facts(
facts: &mut AllFacts, facts: &mut PoloniusFacts,
borrow_set: &BorrowSet<'_>, borrow_set: &BorrowSet<'_>,
universal_region_relations: &UniversalRegionRelations<'_>, universal_region_relations: &UniversalRegionRelations<'_>,
) { ) {
@ -187,10 +187,10 @@ pub(crate) fn emit_drop_facts<'tcx>(
local: Local, local: Local,
kind: &GenericArg<'tcx>, kind: &GenericArg<'tcx>,
universal_regions: &UniversalRegions<'tcx>, universal_regions: &UniversalRegions<'tcx>,
all_facts: &mut Option<AllFacts>, facts: &mut Option<PoloniusFacts>,
) { ) {
debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind); debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind);
let Some(facts) = all_facts.as_mut() else { return }; let Some(facts) = facts.as_mut() else { return };
let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
tcx.for_each_free_region(kind, |drop_live_region| { tcx.for_each_free_region(kind, |drop_live_region| {
let region_vid = universal_regions.to_region_vid(drop_live_region); let region_vid = universal_regions.to_region_vid(drop_live_region);
@ -201,8 +201,8 @@ pub(crate) fn emit_drop_facts<'tcx>(
/// Emit facts about the outlives constraints: the `subset` base relation, i.e. not a transitive /// Emit facts about the outlives constraints: the `subset` base relation, i.e. not a transitive
/// closure. /// closure.
fn emit_outlives_facts<'tcx>( fn emit_outlives_facts<'tcx>(
facts: &mut AllFacts, facts: &mut PoloniusFacts,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
constraints: &MirTypeckRegionConstraints<'tcx>, constraints: &MirTypeckRegionConstraints<'tcx>,
) { ) {
facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map( facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map(

View file

@ -392,7 +392,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
var_infos: VarInfos, var_infos: VarInfos,
constraints: MirTypeckRegionConstraints<'tcx>, constraints: MirTypeckRegionConstraints<'tcx>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
elements: Rc<DenseLocationMap>, location_map: Rc<DenseLocationMap>,
) -> Self { ) -> Self {
let universal_regions = &universal_region_relations.universal_regions; let universal_regions = &universal_region_relations.universal_regions;
let MirTypeckRegionConstraints { let MirTypeckRegionConstraints {
@ -436,7 +436,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
} }
let mut scc_values = let mut scc_values =
RegionValues::new(elements, universal_regions.len(), placeholder_indices); RegionValues::new(location_map, universal_regions.len(), placeholder_indices);
for region in liveness_constraints.regions() { for region in liveness_constraints.regions() {
let scc = constraint_sccs.scc(region); let scc = constraint_sccs.scc(region);

View file

@ -38,7 +38,7 @@ pub(crate) enum RegionElement {
/// an interval matrix storing liveness ranges for each region-vid. /// an interval matrix storing liveness ranges for each region-vid.
pub(crate) struct LivenessValues { pub(crate) struct LivenessValues {
/// The map from locations to points. /// The map from locations to points.
elements: Rc<DenseLocationMap>, location_map: Rc<DenseLocationMap>,
/// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and /// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and
/// currently only used for validating promoteds (which don't care about more precise tracking). /// currently only used for validating promoteds (which don't care about more precise tracking).
@ -77,11 +77,11 @@ impl LiveLoans {
impl LivenessValues { impl LivenessValues {
/// Create an empty map of regions to locations where they're live. /// Create an empty map of regions to locations where they're live.
pub(crate) fn with_specific_points(elements: Rc<DenseLocationMap>) -> Self { pub(crate) fn with_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
LivenessValues { LivenessValues {
live_regions: None, live_regions: None,
points: Some(SparseIntervalMatrix::new(elements.num_points())), points: Some(SparseIntervalMatrix::new(location_map.num_points())),
elements, location_map,
loans: None, loans: None,
} }
} }
@ -90,11 +90,11 @@ impl LivenessValues {
/// ///
/// Unlike `with_specific_points`, does not track exact locations where something is live, only /// Unlike `with_specific_points`, does not track exact locations where something is live, only
/// which regions are live. /// which regions are live.
pub(crate) fn without_specific_points(elements: Rc<DenseLocationMap>) -> Self { pub(crate) fn without_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
LivenessValues { LivenessValues {
live_regions: Some(Default::default()), live_regions: Some(Default::default()),
points: None, points: None,
elements, location_map,
loans: None, loans: None,
} }
} }
@ -122,11 +122,11 @@ impl LivenessValues {
/// Records `region` as being live at the given `location`. /// Records `region` as being live at the given `location`.
pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) { pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
let point = self.elements.point_from_location(location); let point = self.location_map.point_from_location(location);
debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
if let Some(points) = &mut self.points { if let Some(points) = &mut self.points {
points.insert(region, point); points.insert(region, point);
} else if self.elements.point_in_range(point) { } else if self.location_map.point_in_range(point) {
self.live_regions.as_mut().unwrap().insert(region); self.live_regions.as_mut().unwrap().insert(region);
} }
@ -143,7 +143,7 @@ impl LivenessValues {
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
if let Some(this) = &mut self.points { if let Some(this) = &mut self.points {
this.union_row(region, points); this.union_row(region, points);
} else if points.iter().any(|point| self.elements.point_in_range(point)) { } else if points.iter().any(|point| self.location_map.point_in_range(point)) {
self.live_regions.as_mut().unwrap().insert(region); self.live_regions.as_mut().unwrap().insert(region);
} }
@ -170,7 +170,7 @@ impl LivenessValues {
/// Returns whether `region` is marked live at the given `location`. /// Returns whether `region` is marked live at the given `location`.
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool { pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
let point = self.elements.point_from_location(location); let point = self.location_map.point_from_location(location);
if let Some(points) = &self.points { if let Some(points) = &self.points {
points.row(region).is_some_and(|r| r.contains(point)) points.row(region).is_some_and(|r| r.contains(point))
} else { } else {
@ -191,25 +191,26 @@ impl LivenessValues {
.row(region) .row(region)
.into_iter() .into_iter()
.flat_map(|set| set.iter()) .flat_map(|set| set.iter())
.take_while(|&p| self.elements.point_in_range(p)) .take_while(|&p| self.location_map.point_in_range(p))
} }
/// For debugging purposes, returns a pretty-printed string of the points where the `region` is /// For debugging purposes, returns a pretty-printed string of the points where the `region` is
/// live. /// live.
pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String { pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
pretty_print_region_elements( pretty_print_region_elements(
self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))), self.live_points(region)
.map(|p| RegionElement::Location(self.location_map.to_location(p))),
) )
} }
#[inline] #[inline]
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
self.elements.point_from_location(location) self.location_map.point_from_location(location)
} }
#[inline] #[inline]
pub(crate) fn location_from_point(&self, point: PointIndex) -> Location { pub(crate) fn location_from_point(&self, point: PointIndex) -> Location {
self.elements.to_location(point) self.location_map.to_location(point)
} }
/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`. /// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
@ -272,7 +273,7 @@ impl PlaceholderIndices {
/// because (since it is returned) it must live for at least `'a`. But /// because (since it is returned) it must live for at least `'a`. But
/// it would also contain various points from within the function. /// it would also contain various points from within the function.
pub(crate) struct RegionValues<N: Idx> { pub(crate) struct RegionValues<N: Idx> {
elements: Rc<DenseLocationMap>, location_map: Rc<DenseLocationMap>,
placeholder_indices: PlaceholderIndices, placeholder_indices: PlaceholderIndices,
points: SparseIntervalMatrix<N, PointIndex>, points: SparseIntervalMatrix<N, PointIndex>,
free_regions: SparseBitMatrix<N, RegionVid>, free_regions: SparseBitMatrix<N, RegionVid>,
@ -287,14 +288,14 @@ impl<N: Idx> RegionValues<N> {
/// Each of the regions in num_region_variables will be initialized with an /// Each of the regions in num_region_variables will be initialized with an
/// empty set of points and no causal information. /// empty set of points and no causal information.
pub(crate) fn new( pub(crate) fn new(
elements: Rc<DenseLocationMap>, location_map: Rc<DenseLocationMap>,
num_universal_regions: usize, num_universal_regions: usize,
placeholder_indices: PlaceholderIndices, placeholder_indices: PlaceholderIndices,
) -> Self { ) -> Self {
let num_points = elements.num_points(); let num_points = location_map.num_points();
let num_placeholders = placeholder_indices.len(); let num_placeholders = placeholder_indices.len();
Self { Self {
elements, location_map,
points: SparseIntervalMatrix::new(num_points), points: SparseIntervalMatrix::new(num_points),
placeholder_indices, placeholder_indices,
free_regions: SparseBitMatrix::new(num_universal_regions), free_regions: SparseBitMatrix::new(num_universal_regions),
@ -336,7 +337,7 @@ impl<N: Idx> RegionValues<N> {
end: usize, end: usize,
) -> Option<usize> { ) -> Option<usize> {
let row = self.points.row(r)?; let row = self.points.row(r)?;
let block = self.elements.entry_point(block); let block = self.location_map.entry_point(block);
let start = block.plus(start); let start = block.plus(start);
let end = block.plus(end); let end = block.plus(end);
let first_unset = row.first_unset_in(start..=end)?; let first_unset = row.first_unset_in(start..=end)?;
@ -375,8 +376,8 @@ impl<N: Idx> RegionValues<N> {
pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a { pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
self.points.row(r).into_iter().flat_map(move |set| { self.points.row(r).into_iter().flat_map(move |set| {
set.iter() set.iter()
.take_while(move |&p| self.elements.point_in_range(p)) .take_while(move |&p| self.location_map.point_in_range(p))
.map(move |p| self.elements.to_location(p)) .map(move |p| self.location_map.to_location(p))
}) })
} }
@ -430,12 +431,12 @@ pub(crate) trait ToElementIndex: Debug + Copy {
impl ToElementIndex for Location { impl ToElementIndex for Location {
fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool { fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
let index = values.elements.point_from_location(self); let index = values.location_map.point_from_location(self);
values.points.insert(row, index) values.points.insert(row, index)
} }
fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool { fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
let index = values.elements.point_from_location(self); let index = values.location_map.point_from_location(self);
values.points.contains(row, index) values.points.contains(row, index)
} }
} }
@ -464,14 +465,14 @@ impl ToElementIndex for ty::PlaceholderRegion {
/// For debugging purposes, returns a pretty-printed string of the given points. /// For debugging purposes, returns a pretty-printed string of the given points.
pub(crate) fn pretty_print_points( pub(crate) fn pretty_print_points(
elements: &DenseLocationMap, location_map: &DenseLocationMap,
points: impl IntoIterator<Item = PointIndex>, points: impl IntoIterator<Item = PointIndex>,
) -> String { ) -> String {
pretty_print_region_elements( pretty_print_region_elements(
points points
.into_iter() .into_iter()
.take_while(|&p| elements.point_in_range(p)) .take_while(|&p| location_map.point_in_range(p))
.map(|p| elements.to_location(p)) .map(|p| location_map.to_location(p))
.map(RegionElement::Location), .map(RegionElement::Location),
) )
} }

View file

@ -82,7 +82,7 @@ impl<'a> Iterator for AppearancesIter<'a> {
impl LocalUseMap { impl LocalUseMap {
pub(crate) fn build( pub(crate) fn build(
live_locals: &[Local], live_locals: &[Local],
elements: &DenseLocationMap, location_map: &DenseLocationMap,
body: &Body<'_>, body: &Body<'_>,
) -> Self { ) -> Self {
let nones = IndexVec::from_elem(None, &body.local_decls); let nones = IndexVec::from_elem(None, &body.local_decls);
@ -101,7 +101,7 @@ impl LocalUseMap {
IndexVec::from_elem(false, &body.local_decls); IndexVec::from_elem(false, &body.local_decls);
live_locals.iter().for_each(|&local| locals_with_use_data[local] = true); live_locals.iter().for_each(|&local| locals_with_use_data[local] = true);
LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data } LocalUseMapBuild { local_use_map: &mut local_use_map, location_map, locals_with_use_data }
.visit_body(body); .visit_body(body);
local_use_map local_use_map
@ -125,7 +125,7 @@ impl LocalUseMap {
struct LocalUseMapBuild<'me> { struct LocalUseMapBuild<'me> {
local_use_map: &'me mut LocalUseMap, local_use_map: &'me mut LocalUseMap,
elements: &'me DenseLocationMap, location_map: &'me DenseLocationMap,
// Vector used in `visit_local` to signal which `Local`s do we need // Vector used in `visit_local` to signal which `Local`s do we need
// def/use/drop information on, constructed from `live_locals` (that // def/use/drop information on, constructed from `live_locals` (that
@ -147,7 +147,7 @@ impl Visitor<'_> for LocalUseMapBuild<'_> {
DefUse::Use => &mut self.local_use_map.first_use_at[local], DefUse::Use => &mut self.local_use_map.first_use_at[local],
DefUse::Drop => &mut self.local_use_map.first_drop_at[local], DefUse::Drop => &mut self.local_use_map.first_drop_at[local],
}; };
let point_index = self.elements.point_from_location(location); let point_index = self.location_map.point_from_location(location);
let appearance_index = self let appearance_index = self
.local_use_map .local_use_map
.appearances .appearances

View file

@ -32,7 +32,7 @@ mod trace;
pub(super) fn generate<'a, 'tcx>( pub(super) fn generate<'a, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>, typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
elements: &DenseLocationMap, location_map: &DenseLocationMap,
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
) { ) {
@ -49,7 +49,7 @@ pub(super) fn generate<'a, 'tcx>(
trace::trace( trace::trace(
typeck, typeck,
body, body,
elements, location_map,
flow_inits, flow_inits,
move_data, move_data,
relevant_live_locals, relevant_live_locals,

View file

@ -37,13 +37,13 @@ use crate::type_check::{NormalizeLocation, TypeChecker};
pub(super) fn trace<'a, 'tcx>( pub(super) fn trace<'a, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>, typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
elements: &DenseLocationMap, location_map: &DenseLocationMap,
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
relevant_live_locals: Vec<Local>, relevant_live_locals: Vec<Local>,
boring_locals: Vec<Local>, boring_locals: Vec<Local>,
) { ) {
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body); let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, body);
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region. // When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() { if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
@ -79,7 +79,7 @@ pub(super) fn trace<'a, 'tcx>(
typeck, typeck,
body, body,
flow_inits, flow_inits,
elements, location_map,
local_use_map, local_use_map,
move_data, move_data,
drop_data: FxIndexMap::default(), drop_data: FxIndexMap::default(),
@ -100,7 +100,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> {
typeck: &'a mut TypeChecker<'typeck, 'tcx>, typeck: &'a mut TypeChecker<'typeck, 'tcx>,
/// Defines the `PointIndex` mapping /// Defines the `PointIndex` mapping
elements: &'a DenseLocationMap, location_map: &'a DenseLocationMap,
/// MIR we are analyzing. /// MIR we are analyzing.
body: &'a Body<'tcx>, body: &'a Body<'tcx>,
@ -149,7 +149,7 @@ struct LivenessResults<'a, 'typeck, 'b, 'tcx> {
impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
fn new(cx: LivenessContext<'a, 'typeck, 'b, 'tcx>) -> Self { fn new(cx: LivenessContext<'a, 'typeck, 'b, 'tcx>) -> Self {
let num_points = cx.elements.num_points(); let num_points = cx.location_map.num_points();
LivenessResults { LivenessResults {
cx, cx,
defs: BitSet::new_empty(num_points), defs: BitSet::new_empty(num_points),
@ -213,14 +213,14 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) { fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) {
// This collect is more necessary than immediately apparent // This collect is more necessary than immediately apparent
// because these facts go into `add_drop_live_facts_for()`, // because these facts go into `add_drop_live_facts_for()`,
// which also writes to `all_facts`, and so this is genuinely // which also writes to `polonius_facts`, and so this is genuinely
// a simultaneous overlapping mutable borrow. // a simultaneous overlapping mutable borrow.
// FIXME for future hackers: investigate whether this is // FIXME for future hackers: investigate whether this is
// actually necessary; these facts come from Polonius // actually necessary; these facts come from Polonius
// and probably maybe plausibly does not need to go back in. // and probably maybe plausibly does not need to go back in.
// It may be necessary to just pick out the parts of // It may be necessary to just pick out the parts of
// `add_drop_live_facts_for()` that make sense. // `add_drop_live_facts_for()` that make sense.
let Some(facts) = self.cx.typeck.all_facts.as_ref() else { return }; let Some(facts) = self.cx.typeck.polonius_facts.as_ref() else { return };
let facts_to_add: Vec<_> = { let facts_to_add: Vec<_> = {
let relevant_live_locals: FxIndexSet<_> = let relevant_live_locals: FxIndexSet<_> =
relevant_live_locals.iter().copied().collect(); relevant_live_locals.iter().copied().collect();
@ -240,7 +240,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
.collect() .collect()
}; };
let live_at = IntervalSet::new(self.cx.elements.num_points()); let live_at = IntervalSet::new(self.cx.location_map.num_points());
for (local, local_ty, location) in facts_to_add { for (local, local_ty, location) in facts_to_add {
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &live_at); self.cx.add_drop_live_facts_for(local, local_ty, &[location], &live_at);
} }
@ -279,7 +279,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
// * Inclusively, the block start // * Inclusively, the block start
// * Exclusively, the previous definition (if it's in this block) // * Exclusively, the previous definition (if it's in this block)
// * Exclusively, the previous live_at setting (an optimization) // * Exclusively, the previous live_at setting (an optimization)
let block_start = self.cx.elements.to_block_start(p); let block_start = self.cx.location_map.to_block_start(p);
let previous_defs = self.defs.last_set_in(block_start..=p); let previous_defs = self.defs.last_set_in(block_start..=p);
let previous_live_at = self.use_live_at.last_set_in(block_start..=p); let previous_live_at = self.use_live_at.last_set_in(block_start..=p);
@ -303,12 +303,12 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
// terminators of predecessor basic blocks. Push those onto the // terminators of predecessor basic blocks. Push those onto the
// stack so that the next iteration(s) will process them. // stack so that the next iteration(s) will process them.
let block = self.cx.elements.to_location(block_start).block; let block = self.cx.location_map.to_location(block_start).block;
self.stack.extend( self.stack.extend(
self.cx.body.basic_blocks.predecessors()[block] self.cx.body.basic_blocks.predecessors()[block]
.iter() .iter()
.map(|&pred_bb| self.cx.body.terminator_loc(pred_bb)) .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
.map(|pred_loc| self.cx.elements.point_from_location(pred_loc)), .map(|pred_loc| self.cx.location_map.point_from_location(pred_loc)),
); );
} }
} }
@ -331,7 +331,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
// Find the drops where `local` is initialized. // Find the drops where `local` is initialized.
for drop_point in self.cx.local_use_map.drops(local) { for drop_point in self.cx.local_use_map.drops(local) {
let location = self.cx.elements.to_location(drop_point); let location = self.cx.location_map.to_location(drop_point);
debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,);
if self.cx.initialized_at_terminator(location.block, mpi) if self.cx.initialized_at_terminator(location.block, mpi)
@ -367,7 +367,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
debug!( debug!(
"compute_drop_live_points_for_block(mpi={:?}, term_point={:?})", "compute_drop_live_points_for_block(mpi={:?}, term_point={:?})",
self.cx.move_data.move_paths[mpi].place, self.cx.move_data.move_paths[mpi].place,
self.cx.elements.to_location(term_point), self.cx.location_map.to_location(term_point),
); );
// We are only invoked with terminators where `mpi` is // We are only invoked with terminators where `mpi` is
@ -377,12 +377,15 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
// Otherwise, scan backwards through the statements in the // Otherwise, scan backwards through the statements in the
// block. One of them may be either a definition or use // block. One of them may be either a definition or use
// live point. // live point.
let term_location = self.cx.elements.to_location(term_point); let term_location = self.cx.location_map.to_location(term_point);
debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,); debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,);
let block = term_location.block; let block = term_location.block;
let entry_point = self.cx.elements.entry_point(term_location.block); let entry_point = self.cx.location_map.entry_point(term_location.block);
for p in (entry_point..term_point).rev() { for p in (entry_point..term_point).rev() {
debug!("compute_drop_live_points_for_block: p = {:?}", self.cx.elements.to_location(p)); debug!(
"compute_drop_live_points_for_block: p = {:?}",
self.cx.location_map.to_location(p)
);
if self.defs.contains(p) { if self.defs.contains(p) {
debug!("compute_drop_live_points_for_block: def site"); debug!("compute_drop_live_points_for_block: def site");
@ -428,7 +431,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
} }
let pred_term_loc = self.cx.body.terminator_loc(pred_block); let pred_term_loc = self.cx.body.terminator_loc(pred_block);
let pred_term_point = self.cx.elements.point_from_location(pred_term_loc); let pred_term_point = self.cx.location_map.point_from_location(pred_term_loc);
// If the terminator of this predecessor either *assigns* // If the terminator of this predecessor either *assigns*
// our value or is a "normal use", then stop. // our value or is a "normal use", then stop.
@ -523,7 +526,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
/// points `live_at`. /// points `live_at`.
fn add_use_live_facts_for(&mut self, value: Ty<'tcx>, live_at: &IntervalSet<PointIndex>) { fn add_use_live_facts_for(&mut self, value: Ty<'tcx>, live_at: &IntervalSet<PointIndex>) {
debug!("add_use_live_facts_for(value={:?})", value); debug!("add_use_live_facts_for(value={:?})", value);
Self::make_all_regions_live(self.elements, self.typeck, value, live_at); Self::make_all_regions_live(self.location_map, self.typeck, value, live_at);
} }
/// Some variable with type `live_ty` is "drop live" at `location` /// Some variable with type `live_ty` is "drop live" at `location`
@ -547,7 +550,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
dropped_local, dropped_local,
dropped_ty, dropped_ty,
drop_locations, drop_locations,
values::pretty_print_points(self.elements, live_at.iter()), values::pretty_print_points(self.location_map, live_at.iter()),
); );
let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({ let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
@ -574,19 +577,19 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
// All things in the `outlives` array may be touched by // All things in the `outlives` array may be touched by
// the destructor and must be live at this point. // the destructor and must be live at this point.
for &kind in &drop_data.dropck_result.kinds { for &kind in &drop_data.dropck_result.kinds {
Self::make_all_regions_live(self.elements, self.typeck, kind, live_at); Self::make_all_regions_live(self.location_map, self.typeck, kind, live_at);
polonius::legacy::emit_drop_facts( polonius::legacy::emit_drop_facts(
self.typeck.tcx(), self.typeck.tcx(),
dropped_local, dropped_local,
&kind, &kind,
self.typeck.universal_regions, self.typeck.universal_regions,
self.typeck.all_facts, self.typeck.polonius_facts,
); );
} }
} }
fn make_all_regions_live( fn make_all_regions_live(
elements: &DenseLocationMap, location_map: &DenseLocationMap,
typeck: &mut TypeChecker<'_, 'tcx>, typeck: &mut TypeChecker<'_, 'tcx>,
value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>, value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
live_at: &IntervalSet<PointIndex>, live_at: &IntervalSet<PointIndex>,
@ -594,7 +597,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
debug!("make_all_regions_live(value={:?})", value); debug!("make_all_regions_live(value={:?})", value);
debug!( debug!(
"make_all_regions_live: live_at={}", "make_all_regions_live: live_at={}",
values::pretty_print_points(elements, live_at.iter()), values::pretty_print_points(location_map, live_at.iter()),
); );
value.visit_with(&mut for_liveness::FreeRegionsVisitor { value.visit_with(&mut for_liveness::FreeRegionsVisitor {

View file

@ -49,7 +49,7 @@ use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
use crate::diagnostics::UniverseInfo; use crate::diagnostics::UniverseInfo;
use crate::member_constraints::MemberConstraintSet; use crate::member_constraints::MemberConstraintSet;
use crate::polonius::PoloniusContext; use crate::polonius::PoloniusContext;
use crate::polonius::legacy::{AllFacts, LocationTable}; use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable};
use crate::region_infer::TypeTest; use crate::region_infer::TypeTest;
use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}; use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
use crate::renumber::RegionCtxt; use crate::renumber::RegionCtxt;
@ -98,29 +98,29 @@ mod relate_tys;
/// - `body` -- MIR body to type-check /// - `body` -- MIR body to type-check
/// - `promoted` -- map of promoted constants within `body` /// - `promoted` -- map of promoted constants within `body`
/// - `universal_regions` -- the universal regions from `body`s function signature /// - `universal_regions` -- the universal regions from `body`s function signature
/// - `location_table` -- MIR location map of `body` /// - `location_table` -- for datalog polonius, the map between `Location`s and `RichLocation`s
/// - `borrow_set` -- information about borrows occurring in `body` /// - `borrow_set` -- information about borrows occurring in `body`
/// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts /// - `polonius_facts` -- when using Polonius, this is the generated set of Polonius facts
/// - `flow_inits` -- results of a maybe-init dataflow analysis /// - `flow_inits` -- results of a maybe-init dataflow analysis
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
/// - `elements` -- MIR region map /// - `location_map` -- map between MIR `Location` and `PointIndex`
pub(crate) fn type_check<'a, 'tcx>( pub(crate) fn type_check<'a, 'tcx>(
infcx: &BorrowckInferCtxt<'tcx>, infcx: &BorrowckInferCtxt<'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
promoted: &IndexSlice<Promoted, Body<'tcx>>, promoted: &IndexSlice<Promoted, Body<'tcx>>,
universal_regions: UniversalRegions<'tcx>, universal_regions: UniversalRegions<'tcx>,
location_table: &LocationTable, location_table: &PoloniusLocationTable,
borrow_set: &BorrowSet<'tcx>, borrow_set: &BorrowSet<'tcx>,
all_facts: &mut Option<AllFacts>, polonius_facts: &mut Option<PoloniusFacts>,
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
elements: Rc<DenseLocationMap>, location_map: Rc<DenseLocationMap>,
) -> MirTypeckResults<'tcx> { ) -> MirTypeckResults<'tcx> {
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
let mut constraints = MirTypeckRegionConstraints { let mut constraints = MirTypeckRegionConstraints {
placeholder_indices: PlaceholderIndices::default(), placeholder_indices: PlaceholderIndices::default(),
placeholder_index_to_region: IndexVec::default(), placeholder_index_to_region: IndexVec::default(),
liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&elements)), liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&location_map)),
outlives_constraints: OutlivesConstraintSet::default(), outlives_constraints: OutlivesConstraintSet::default(),
member_constraints: MemberConstraintSet::default(), member_constraints: MemberConstraintSet::default(),
type_tests: Vec::default(), type_tests: Vec::default(),
@ -165,7 +165,7 @@ pub(crate) fn type_check<'a, 'tcx>(
reported_errors: Default::default(), reported_errors: Default::default(),
universal_regions: &universal_region_relations.universal_regions, universal_regions: &universal_region_relations.universal_regions,
location_table, location_table,
all_facts, polonius_facts,
borrow_set, borrow_set,
constraints: &mut constraints, constraints: &mut constraints,
polonius_context: &mut polonius_context, polonius_context: &mut polonius_context,
@ -180,7 +180,7 @@ pub(crate) fn type_check<'a, 'tcx>(
typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output); typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output);
typeck.check_signature_annotation(body); typeck.check_signature_annotation(body);
liveness::generate(&mut typeck, body, &elements, flow_inits, move_data); liveness::generate(&mut typeck, body, &location_map, flow_inits, move_data);
let opaque_type_values = let opaque_type_values =
opaque_types::take_opaques_and_register_member_constraints(&mut typeck); opaque_types::take_opaques_and_register_member_constraints(&mut typeck);
@ -495,14 +495,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// Use new sets of constraints and closure bounds so that we can // Use new sets of constraints and closure bounds so that we can
// modify their locations. // modify their locations.
let all_facts = &mut None; let polonius_facts = &mut None;
let mut constraints = Default::default(); let mut constraints = Default::default();
let mut liveness_constraints = let mut liveness_constraints =
LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body))); LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body)));
// Don't try to add borrow_region facts for the promoted MIR // Don't try to add borrow_region facts for the promoted MIR
let mut swap_constraints = |this: &mut Self| { let mut swap_constraints = |this: &mut Self| {
mem::swap(this.typeck.all_facts, all_facts); mem::swap(this.typeck.polonius_facts, polonius_facts);
mem::swap(&mut this.typeck.constraints.outlives_constraints, &mut constraints); mem::swap(&mut this.typeck.constraints.outlives_constraints, &mut constraints);
mem::swap(&mut this.typeck.constraints.liveness_constraints, &mut liveness_constraints); mem::swap(&mut this.typeck.constraints.liveness_constraints, &mut liveness_constraints);
}; };
@ -560,8 +560,8 @@ struct TypeChecker<'a, 'tcx> {
implicit_region_bound: ty::Region<'tcx>, implicit_region_bound: ty::Region<'tcx>,
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
universal_regions: &'a UniversalRegions<'tcx>, universal_regions: &'a UniversalRegions<'tcx>,
location_table: &'a LocationTable, location_table: &'a PoloniusLocationTable,
all_facts: &'a mut Option<AllFacts>, polonius_facts: &'a mut Option<PoloniusFacts>,
borrow_set: &'a BorrowSet<'tcx>, borrow_set: &'a BorrowSet<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
/// When using `-Zpolonius=next`, the helper data used to create polonius constraints. /// When using `-Zpolonius=next`, the helper data used to create polonius constraints.
@ -2341,18 +2341,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
borrowed_place: &Place<'tcx>, borrowed_place: &Place<'tcx>,
) { ) {
// These constraints are only meaningful during borrowck: // These constraints are only meaningful during borrowck:
let Self { borrow_set, location_table, all_facts, constraints, .. } = self; let Self { borrow_set, location_table, polonius_facts, constraints, .. } = self;
// In Polonius mode, we also push a `loan_issued_at` fact // In Polonius mode, we also push a `loan_issued_at` fact
// linking the loan to the region (in some cases, though, // linking the loan to the region (in some cases, though,
// there is no loan associated with this borrow expression -- // there is no loan associated with this borrow expression --
// that occurs when we are borrowing an unsafe place, for // that occurs when we are borrowing an unsafe place, for
// example). // example).
if let Some(all_facts) = all_facts { if let Some(polonius_facts) = polonius_facts {
let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
if let Some(borrow_index) = borrow_set.get_index_of(&location) { if let Some(borrow_index) = borrow_set.get_index_of(&location) {
let region_vid = borrow_region.as_var(); let region_vid = borrow_region.as_var();
all_facts.loan_issued_at.push(( polonius_facts.loan_issued_at.push((
region_vid.into(), region_vid.into(),
borrow_index, borrow_index,
location_table.mid_index(location), location_table.mid_index(location),

View file

@ -522,7 +522,7 @@ impl MacResult for MacEager {
return Some(P(ast::Pat { return Some(P(ast::Pat {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
span: e.span, span: e.span,
kind: PatKind::Lit(e), kind: PatKind::Expr(e),
tokens: None, tokens: None,
})); }));
} }

View file

@ -486,7 +486,7 @@ impl<'a> ExtCtxt<'a> {
self.pat(span, PatKind::Wild) self.pat(span, PatKind::Wild)
} }
pub fn pat_lit(&self, span: Span, expr: P<ast::Expr>) -> P<ast::Pat> { pub fn pat_lit(&self, span: Span, expr: P<ast::Expr>) -> P<ast::Pat> {
self.pat(span, PatKind::Lit(expr)) self.pat(span, PatKind::Expr(expr))
} }
pub fn pat_ident(&self, span: Span, ident: Ident) -> P<ast::Pat> { pub fn pat_ident(&self, span: Span, ident: Ident) -> P<ast::Pat> {
self.pat_ident_binding_mode(span, ident, ast::BindingMode::NONE) self.pat_ident_binding_mode(span, ident, ast::BindingMode::NONE)

View file

@ -1386,7 +1386,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*; use PatKind::*;
match self.kind { match self.kind {
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true, Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it), Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
@ -1413,7 +1413,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*; use PatKind::*;
match self.kind { match self.kind {
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {} Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it), Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
@ -1519,6 +1519,26 @@ impl fmt::Debug for DotDotPos {
} }
} }
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct PatExpr<'hir> {
pub hir_id: HirId,
pub span: Span,
pub kind: PatExprKind<'hir>,
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum PatExprKind<'hir> {
Lit {
lit: &'hir Lit,
// FIXME: move this into `Lit` and handle negated literal expressions
// once instead of matching on unop neg expressions everywhere.
negated: bool,
},
ConstBlock(ConstBlock),
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
Path(QPath<'hir>),
}
#[derive(Debug, Clone, Copy, HashStable_Generic)] #[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum PatKind<'hir> { pub enum PatKind<'hir> {
/// Represents a wildcard pattern (i.e., `_`). /// Represents a wildcard pattern (i.e., `_`).
@ -1563,14 +1583,14 @@ pub enum PatKind<'hir> {
/// A reference pattern (e.g., `&mut (a, b)`). /// A reference pattern (e.g., `&mut (a, b)`).
Ref(&'hir Pat<'hir>, Mutability), Ref(&'hir Pat<'hir>, Mutability),
/// A literal. /// A literal, const block or path.
Lit(&'hir Expr<'hir>), Expr(&'hir PatExpr<'hir>),
/// A guard pattern (e.g., `x if guard(x)`). /// A guard pattern (e.g., `x if guard(x)`).
Guard(&'hir Pat<'hir>, &'hir Expr<'hir>), Guard(&'hir Pat<'hir>, &'hir Expr<'hir>),
/// A range pattern (e.g., `1..=2` or `1..2`). /// A range pattern (e.g., `1..=2` or `1..2`).
Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd), Range(Option<&'hir PatExpr<'hir>>, Option<&'hir PatExpr<'hir>>, RangeEnd),
/// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`. /// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
/// ///
@ -4144,6 +4164,10 @@ pub enum Node<'hir> {
OpaqueTy(&'hir OpaqueTy<'hir>), OpaqueTy(&'hir OpaqueTy<'hir>),
Pat(&'hir Pat<'hir>), Pat(&'hir Pat<'hir>),
PatField(&'hir PatField<'hir>), PatField(&'hir PatField<'hir>),
/// Needed as its own node with its own HirId for tracking
/// the unadjusted type of literals within patterns
/// (e.g. byte str literals not being of slice type).
PatExpr(&'hir PatExpr<'hir>),
Arm(&'hir Arm<'hir>), Arm(&'hir Arm<'hir>),
Block(&'hir Block<'hir>), Block(&'hir Block<'hir>),
LetStmt(&'hir LetStmt<'hir>), LetStmt(&'hir LetStmt<'hir>),
@ -4200,6 +4224,7 @@ impl<'hir> Node<'hir> {
| Node::Block(..) | Node::Block(..)
| Node::Ctor(..) | Node::Ctor(..)
| Node::Pat(..) | Node::Pat(..)
| Node::PatExpr(..)
| Node::Arm(..) | Node::Arm(..)
| Node::LetStmt(..) | Node::LetStmt(..)
| Node::Crate(..) | Node::Crate(..)

View file

@ -342,6 +342,9 @@ pub trait Visitor<'v>: Sized {
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result { fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
walk_pat_field(self, f) walk_pat_field(self, f)
} }
fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result {
walk_pat_expr(self, expr)
}
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
walk_anon_const(self, c) walk_anon_const(self, c)
} }
@ -685,10 +688,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ident(ident));
visit_opt!(visitor, visit_pat, optional_subpattern); visit_opt!(visitor, visit_pat, optional_subpattern);
} }
PatKind::Lit(ref expression) => try_visit!(visitor.visit_expr(expression)), PatKind::Expr(ref expression) => try_visit!(visitor.visit_pat_expr(expression)),
PatKind::Range(ref lower_bound, ref upper_bound, _) => { PatKind::Range(ref lower_bound, ref upper_bound, _) => {
visit_opt!(visitor, visit_expr, lower_bound); visit_opt!(visitor, visit_pat_expr, lower_bound);
visit_opt!(visitor, visit_expr, upper_bound); visit_opt!(visitor, visit_pat_expr, upper_bound);
} }
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (), PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => { PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
@ -710,6 +713,15 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
visitor.visit_pat(field.pat) visitor.visit_pat(field.pat)
} }
pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result {
try_visit!(visitor.visit_id(expr.hir_id));
match &expr.kind {
PatExprKind::Lit { .. } => V::Result::output(),
PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c),
PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span),
}
}
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result { pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result {
try_visit!(visitor.visit_id(constant.hir_id)); try_visit!(visitor.visit_id(constant.hir_id));
visitor.visit_nested_body(constant.body) visitor.visit_nested_body(constant.body)

View file

@ -704,7 +704,7 @@ fn resolve_local<'tcx>(
| PatKind::Wild | PatKind::Wild
| PatKind::Never | PatKind::Never
| PatKind::Path(_) | PatKind::Path(_)
| PatKind::Lit(_) | PatKind::Expr(_)
| PatKind::Range(_, _, _) | PatKind::Range(_, _, _)
| PatKind::Err(_) => false, | PatKind::Err(_) => false,
} }

View file

@ -2449,17 +2449,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Ty::new_error(tcx, err) Ty::new_error(tcx, err)
} }
hir::PatKind::Range(start, end, include_end) => { hir::PatKind::Range(start, end, include_end) => {
let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> { let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
let (expr, neg) = match expr.kind { let (c, c_ty) = match expr.kind {
hir::ExprKind::Unary(hir::UnOp::Neg, negated) => { hir::PatExprKind::Lit { lit, negated } => {
(negated, Some((expr.hir_id, expr.span)))
}
_ => (expr, None),
};
let (c, c_ty) = match &expr.kind {
hir::ExprKind::Lit(lit) => {
let lit_input = let lit_input =
LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() }; LitToConstInput { lit: &lit.node, ty, neg: negated };
let ct = match tcx.lit_to_const(lit_input) { let ct = match tcx.lit_to_const(lit_input) {
Ok(c) => c, Ok(c) => c,
Err(LitToConstError::Reported(err)) => { Err(LitToConstError::Reported(err)) => {
@ -2470,23 +2464,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
(ct, ty) (ct, ty)
} }
hir::ExprKind::Path(hir::QPath::Resolved( hir::PatExprKind::Path(hir::QPath::Resolved(
_, _,
path @ &hir::Path { path @ &hir::Path {
res: Res::Def(DefKind::ConstParam, def_id), res: Res::Def(DefKind::ConstParam, def_id),
.. ..
}, },
)) => { )) => {
let _ = self.prohibit_generic_args( match self.prohibit_generic_args(
path.segments.iter(), path.segments.iter(),
GenericsArgsErrExtend::Param(def_id), GenericsArgsErrExtend::Param(def_id),
); ) {
let ty = tcx Ok(()) => {
.type_of(def_id) let ty = tcx
.no_bound_vars() .type_of(def_id)
.expect("const parameter types cannot be generic"); .no_bound_vars()
let ct = self.lower_const_param(def_id, expr.hir_id); .expect("const parameter types cannot be generic");
(ct, ty) 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),
),
}
} }
_ => { _ => {
@ -2497,9 +2498,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
}; };
self.record_ty(expr.hir_id, c_ty, expr.span); self.record_ty(expr.hir_id, c_ty, expr.span);
if let Some((id, span)) = neg {
self.record_ty(id, c_ty, span);
}
c c
}; };

View file

@ -199,6 +199,7 @@ impl<'a> State<'a> {
Node::OpaqueTy(o) => self.print_opaque_ty(o), Node::OpaqueTy(o) => self.print_opaque_ty(o),
Node::Pat(a) => self.print_pat(a), Node::Pat(a) => self.print_pat(a),
Node::PatField(a) => self.print_patfield(a), Node::PatField(a) => self.print_patfield(a),
Node::PatExpr(a) => self.print_pat_expr(a),
Node::Arm(a) => self.print_arm(a), Node::Arm(a) => self.print_arm(a),
Node::Infer(_) => self.word("_"), Node::Infer(_) => self.word("_"),
Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident), Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident),
@ -1849,6 +1850,19 @@ impl<'a> State<'a> {
} }
} }
fn print_pat_expr(&mut self, expr: &hir::PatExpr<'_>) {
match &expr.kind {
hir::PatExprKind::Lit { lit, negated } => {
if *negated {
self.word("-");
}
self.print_literal(lit);
}
hir::PatExprKind::ConstBlock(c) => self.print_inline_const(c),
hir::PatExprKind::Path(qpath) => self.print_qpath(qpath, true),
}
}
fn print_pat(&mut self, pat: &hir::Pat<'_>) { fn print_pat(&mut self, pat: &hir::Pat<'_>) {
self.maybe_print_comment(pat.span.lo()); self.maybe_print_comment(pat.span.lo());
self.ann.pre(self, AnnNode::Pat(pat)); self.ann.pre(self, AnnNode::Pat(pat));
@ -1966,17 +1980,17 @@ impl<'a> State<'a> {
self.pclose(); self.pclose();
} }
} }
PatKind::Lit(e) => self.print_expr(e), PatKind::Expr(e) => self.print_pat_expr(e),
PatKind::Range(begin, end, end_kind) => { PatKind::Range(begin, end, end_kind) => {
if let Some(expr) = begin { if let Some(expr) = begin {
self.print_expr(expr); self.print_pat_expr(expr);
} }
match end_kind { match end_kind {
RangeEnd::Included => self.word("..."), RangeEnd::Included => self.word("..."),
RangeEnd::Excluded => self.word(".."), RangeEnd::Excluded => self.word(".."),
} }
if let Some(expr) = end { if let Some(expr) = end {
self.print_expr(expr); self.print_pat_expr(expr);
} }
} }
PatKind::Slice(before, slice, after) => { PatKind::Slice(before, slice, after) => {

View file

@ -430,6 +430,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| hir::Node::AssocItemConstraint(_) | hir::Node::AssocItemConstraint(_)
| hir::Node::TraitRef(_) | hir::Node::TraitRef(_)
| hir::Node::PatField(_) | hir::Node::PatField(_)
| hir::Node::PatExpr(_)
| hir::Node::LetStmt(_) | hir::Node::LetStmt(_)
| hir::Node::Synthetic | hir::Node::Synthetic
| hir::Node::Err(_) | hir::Node::Err(_)
@ -484,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| hir::PatKind::Box(_) | hir::PatKind::Box(_)
| hir::PatKind::Ref(_, _) | hir::PatKind::Ref(_, _)
| hir::PatKind::Deref(_) | hir::PatKind::Deref(_)
| hir::PatKind::Lit(_) | hir::PatKind::Expr(_)
| hir::PatKind::Range(_, _, _) | hir::PatKind::Range(_, _, _)
| hir::PatKind::Slice(_, _, _) | hir::PatKind::Slice(_, _, _)
| hir::PatKind::Err(_) => true, | hir::PatKind::Err(_) => true,
@ -837,7 +838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We always require that the type provided as the value for // We always require that the type provided as the value for
// a type parameter outlives the moment of instantiation. // a type parameter outlives the moment of instantiation.
let args = self.typeck_results.borrow().node_args(expr.hir_id); let args = self.typeck_results.borrow().node_args(expr.hir_id);
self.add_wf_bounds(args, expr); self.add_wf_bounds(args, expr.span);
ty ty
} }
@ -1796,7 +1797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
fn check_expr_const_block( pub(super) fn check_expr_const_block(
&self, &self,
block: &'tcx hir::ConstBlock, block: &'tcx hir::ConstBlock,
expected: Expectation<'tcx>, expected: Expectation<'tcx>,

View file

@ -595,7 +595,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
let place_ty = place.place.ty(); let place_ty = place.place.ty();
needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span); needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
} }
PatKind::Lit(_) | PatKind::Range(..) => { PatKind::Expr(_) | PatKind::Range(..) => {
// If the PatKind is a Lit or a Range then we want // If the PatKind is a Lit or a Range then we want
// to borrow discr. // to borrow discr.
needs_to_be_read = true; needs_to_be_read = true;
@ -1803,7 +1803,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
PatKind::Path(_) PatKind::Path(_)
| PatKind::Binding(.., None) | PatKind::Binding(.., None)
| PatKind::Lit(..) | PatKind::Expr(..)
| PatKind::Range(..) | PatKind::Range(..)
| PatKind::Never | PatKind::Never
| PatKind::Wild | PatKind::Wild

View file

@ -577,11 +577,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
/// Registers obligations that all `args` are well-formed. /// Registers obligations that all `args` are well-formed.
pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &hir::Expr<'_>) { pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, span: Span) {
for arg in args.iter().filter(|arg| { for arg in args.iter().filter(|arg| {
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
}) { }) {
self.register_wf_obligation(arg, expr.span, ObligationCauseCode::WellFormed(None)); self.register_wf_obligation(arg, span, ObligationCauseCode::WellFormed(None));
} }
} }
@ -1039,6 +1039,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
def_id, def_id,
span, span,
), ),
Res::Err => {
return (
Ty::new_error(
tcx,
tcx.dcx().span_delayed_bug(span, "could not resolve path {:?}"),
),
res,
);
}
_ => bug!("instantiate_value_path on {:?}", res), _ => bug!("instantiate_value_path on {:?}", res),
}; };

View file

@ -611,7 +611,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// this is a projection from a trait reference, so we have to // this is a projection from a trait reference, so we have to
// make sure that the trait reference inputs are well-formed. // make sure that the trait reference inputs are well-formed.
self.add_wf_bounds(all_args, self.call_expr); self.add_wf_bounds(all_args, self.call_expr.span);
// the function type must also be well-formed (this is not // the function type must also be well-formed (this is not
// implied by the args being well-formed because of inherent // implied by the args being well-formed because of inherent

View file

@ -170,6 +170,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span, span,
.. ..
}) })
| hir::Node::PatExpr(&hir::PatExpr {
kind: hir::PatExprKind::Path(QPath::TypeRelative(rcvr, segment)),
span,
..
})
| hir::Node::Pat(&hir::Pat { | hir::Node::Pat(&hir::Pat {
kind: kind:
hir::PatKind::Path(QPath::TypeRelative(rcvr, segment)) hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))

View file

@ -30,6 +30,7 @@ use tracing::{debug, instrument, trace};
use ty::VariantDef; use ty::VariantDef;
use super::report_unexpected_variant_res; use super::report_unexpected_variant_res;
use crate::expectation::Expectation;
use crate::gather_locals::DeclOrigin; use crate::gather_locals::DeclOrigin;
use crate::{FnCtxt, LoweredTy, errors}; use crate::{FnCtxt, LoweredTy, errors};
@ -270,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PatKind::Wild | PatKind::Err(_) => expected, PatKind::Wild | PatKind::Err(_) => expected,
// We allow any type here; we ensure that the type is uninhabited during match checking. // We allow any type here; we ensure that the type is uninhabited during match checking.
PatKind::Never => expected, PatKind::Never => expected,
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
PatKind::Binding(ba, var_id, ident, sub) => { PatKind::Binding(ba, var_id, ident, sub) => {
self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info) self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
@ -279,7 +280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info) self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
} }
PatKind::Path(ref qpath) => { PatKind::Path(ref qpath) => {
self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) self.check_pat_path(pat.hir_id, pat.span, qpath, path_res.unwrap(), expected, ti)
} }
PatKind::Struct(ref qpath, fields, has_rest_pat) => { PatKind::Struct(ref qpath, fields, has_rest_pat) => {
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info) self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
@ -398,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`. // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
// //
// Call `resolve_vars_if_possible` here for inline const blocks. // Call `resolve_vars_if_possible` here for inline const blocks.
PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() { PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass, ty::Ref(..) => AdjustMode::Pass,
_ => AdjustMode::Peel, _ => AdjustMode::Peel,
}, },
@ -493,10 +494,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(expected, def_br, max_ref_mutbl) (expected, def_br, max_ref_mutbl)
} }
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
let ty = match &lt.kind {
rustc_hir::PatExprKind::Lit { lit, .. } => {
self.check_expr_lit(lit, Expectation::NoExpectation)
}
rustc_hir::PatExprKind::ConstBlock(c) => {
self.check_expr_const_block(c, Expectation::NoExpectation)
}
rustc_hir::PatExprKind::Path(qpath) => {
let (res, opt_ty, segments) =
self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
}
};
self.write_ty(lt.hir_id, ty);
ty
}
fn check_pat_lit( fn check_pat_lit(
&self, &self,
span: Span, span: Span,
lt: &hir::Expr<'tcx>, lt: &hir::PatExpr<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
ti: &TopInfo<'tcx>, ti: &TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
@ -507,7 +526,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Byte string patterns behave the same way as array patterns // Byte string patterns behave the same way as array patterns
// They can denote both statically and dynamically-sized byte arrays. // They can denote both statically and dynamically-sized byte arrays.
let mut pat_ty = ty; let mut pat_ty = ty;
if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind { if let hir::PatExprKind::Lit {
lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
} = lt.kind
{
let expected = self.structurally_resolve_type(span, expected); let expected = self.structurally_resolve_type(span, expected);
if let ty::Ref(_, inner_ty, _) = *expected.kind() if let ty::Ref(_, inner_ty, _) = *expected.kind()
&& self.try_structurally_resolve_type(span, inner_ty).is_slice() && self.try_structurally_resolve_type(span, inner_ty).is_slice()
@ -524,7 +546,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
if self.tcx.features().string_deref_patterns() if self.tcx.features().string_deref_patterns()
&& let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind && let hir::PatExprKind::Lit {
lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
} = lt.kind
{ {
let tcx = self.tcx; let tcx = self.tcx;
let expected = self.resolve_vars_if_possible(expected); let expected = self.resolve_vars_if_possible(expected);
@ -565,15 +589,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_pat_range( fn check_pat_range(
&self, &self,
span: Span, span: Span,
lhs: Option<&'tcx hir::Expr<'tcx>>, lhs: Option<&'tcx hir::PatExpr<'tcx>>,
rhs: Option<&'tcx hir::Expr<'tcx>>, rhs: Option<&'tcx hir::PatExpr<'tcx>>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
ti: &TopInfo<'tcx>, ti: &TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr { let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
None => None, None => None,
Some(expr) => { Some(expr) => {
let ty = self.check_expr(expr); let ty = self.check_pat_expr_unadjusted(expr);
// Check that the end-point is possibly of numeric or char type. // Check that the end-point is possibly of numeric or char type.
// The early check here is not for correctness, but rather better // The early check here is not for correctness, but rather better
// diagnostics (e.g. when `&str` is being matched, `expected` will // diagnostics (e.g. when `&str` is being matched, `expected` will
@ -919,7 +943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| PatKind::Box(..) | PatKind::Box(..)
| PatKind::Deref(_) | PatKind::Deref(_)
| PatKind::Ref(..) | PatKind::Ref(..)
| PatKind::Lit(..) | PatKind::Expr(..)
| PatKind::Range(..) | PatKind::Range(..)
| PatKind::Err(_) => break 'block None, | PatKind::Err(_) => break 'block None,
}, },
@ -1053,7 +1077,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_pat_path( fn check_pat_path(
&self, &self,
pat: &Pat<'tcx>, hir_id: HirId,
span: Span,
qpath: &hir::QPath<'_>, qpath: &hir::QPath<'_>,
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]), path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
expected: Ty<'tcx>, expected: Ty<'tcx>,
@ -1072,8 +1097,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => { Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
let expected = "unit struct, unit variant or constant"; let expected = "unit struct, unit variant or constant";
let e = let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0533, expected);
return Ty::new_error(tcx, e); return Ty::new_error(tcx, e);
} }
Res::SelfCtor(def_id) => { Res::SelfCtor(def_id) => {
@ -1088,7 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
res, res,
None, None,
qpath, qpath,
pat.span, span,
E0533, E0533,
"unit struct", "unit struct",
); );
@ -1107,11 +1131,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Type-check the path. // Type-check the path.
let (pat_ty, pat_res) = let (pat_ty, pat_res) =
self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id); self.instantiate_value_path(segments, opt_ty, res, span, span, hir_id);
if let Err(err) = if let Err(err) =
self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty)
{ {
self.emit_bad_pat_path(err, pat, res, pat_res, pat_ty, segments); self.emit_bad_pat_path(err, hir_id, span, res, pat_res, pat_ty, segments);
} }
pat_ty pat_ty
} }
@ -1154,13 +1178,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn emit_bad_pat_path( fn emit_bad_pat_path(
&self, &self,
mut e: Diag<'_>, mut e: Diag<'_>,
pat: &hir::Pat<'tcx>, hir_id: HirId,
pat_span: Span,
res: Res, res: Res,
pat_res: Res, pat_res: Res,
pat_ty: Ty<'tcx>, pat_ty: Ty<'tcx>,
segments: &'tcx [hir::PathSegment<'tcx>], segments: &'tcx [hir::PathSegment<'tcx>],
) { ) {
let pat_span = pat.span;
if let Some(span) = self.tcx.hir().res_span(pat_res) { if let Some(span) = self.tcx.hir().res_span(pat_res) {
e.span_label(span, format!("{} defined here", res.descr())); e.span_label(span, format!("{} defined here", res.descr()));
if let [hir::PathSegment { ident, .. }] = &*segments { if let [hir::PathSegment { ident, .. }] = &*segments {
@ -1173,7 +1197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
res.descr(), res.descr(),
), ),
); );
match self.tcx.parent_hir_node(pat.hir_id) { match self.tcx.parent_hir_node(hir_id) {
hir::Node::PatField(..) => { hir::Node::PatField(..) => {
e.span_suggestion_verbose( e.span_suggestion_verbose(
ident.span.shrink_to_hi(), ident.span.shrink_to_hi(),
@ -1813,9 +1837,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} else if inexistent_fields.len() == 1 { } else if inexistent_fields.len() == 1 {
match pat_field.pat.kind { match pat_field.pat.kind {
PatKind::Lit(expr) PatKind::Expr(_)
if !self.may_coerce( if !self.may_coerce(
self.typeck_results.borrow().expr_ty(expr), self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
self.field_ty(field.span, field_def, args), self.field_ty(field.span, field_def, args),
) => {} ) => {}
_ => { _ => {

View file

@ -147,15 +147,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
self.visit_body(body); self.visit_body(body);
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause); self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
} }
hir::ExprKind::ConstBlock(anon_const) => {
let body = self.fcx.tcx.hir().body(anon_const.body);
self.visit_body(body);
}
_ => {} _ => {}
} }
intravisit::walk_expr(self, expr); intravisit::walk_expr(self, expr);
} }
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
let body = self.fcx.tcx.hir().body(c.body);
self.visit_body(body);
}
} }
impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

View file

@ -246,6 +246,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
} }
} }
} }
fn visit_const_block(&mut self, span: Span, anon_const: &hir::ConstBlock) {
self.visit_node_id(span, anon_const.hir_id);
let body = self.tcx().hir().body(anon_const.body);
self.visit_body(body);
}
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -275,11 +282,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => { hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
self.visit_field_id(e.hir_id); self.visit_field_id(e.hir_id);
} }
hir::ExprKind::ConstBlock(anon_const) => { hir::ExprKind::ConstBlock(ref anon_const) => {
self.visit_node_id(e.span, anon_const.hir_id); self.visit_const_block(e.span, anon_const);
let body = self.tcx().hir().body(anon_const.body);
self.visit_body(body);
} }
_ => {} _ => {}
} }
@ -335,6 +339,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
intravisit::walk_pat(self, p); intravisit::walk_pat(self, p);
} }
fn visit_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) {
self.visit_node_id(expr.span, expr.hir_id);
if let hir::PatExprKind::ConstBlock(c) = &expr.kind {
self.visit_const_block(expr.span, c);
}
intravisit::walk_pat_expr(self, expr);
}
fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) { fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
intravisit::walk_local(self, l); intravisit::walk_local(self, l);
let var_ty = self.fcx.local_ty(l.span, l.hir_id); let var_ty = self.fcx.local_ty(l.span, l.hir_id);

View file

@ -1220,7 +1220,7 @@ impl EarlyLintPass for UnusedParens {
// Do not lint on `(..)` as that will result in the other arms being useless. // Do not lint on `(..)` as that will result in the other arms being useless.
Paren(_) Paren(_)
// The other cases do not contain sub-patterns. // The other cases do not contain sub-patterns.
| Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {}, | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
// These are list-like patterns; parens can always be removed. // These are list-like patterns; parens can always be removed.
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
self.check_unused_parens_pat(cx, p, false, false, keep_space); self.check_unused_parens_pat(cx, p, false, false, keep_space);

View file

@ -938,6 +938,7 @@ impl<'hir> Map<'hir> {
Node::OpaqueTy(op) => op.span, Node::OpaqueTy(op) => op.span,
Node::Pat(pat) => pat.span, Node::Pat(pat) => pat.span,
Node::PatField(field) => field.span, Node::PatField(field) => field.span,
Node::PatExpr(lit) => lit.span,
Node::Arm(arm) => arm.span, Node::Arm(arm) => arm.span,
Node::Block(block) => block.span, Node::Block(block) => block.span,
Node::Ctor(..) => self.span_with_body(self.tcx.parent_hir_id(hir_id)), Node::Ctor(..) => self.span_with_body(self.tcx.parent_hir_id(hir_id)),
@ -1209,6 +1210,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
Node::OpaqueTy(_) => node_str("opaque type"), Node::OpaqueTy(_) => node_str("opaque type"),
Node::Pat(_) => node_str("pat"), Node::Pat(_) => node_str("pat"),
Node::PatField(_) => node_str("pattern field"), Node::PatField(_) => node_str("pattern field"),
Node::PatExpr(_) => node_str("pattern literal"),
Node::Param(_) => node_str("param"), Node::Param(_) => node_str("param"),
Node::Arm(_) => node_str("arm"), Node::Arm(_) => node_str("arm"),
Node::Block(_) => node_str("block"), Node::Block(_) => node_str("block"),

View file

@ -154,7 +154,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern_range_endpoint( fn lower_pattern_range_endpoint(
&mut self, &mut self,
expr: Option<&'tcx hir::Expr<'tcx>>, expr: Option<&'tcx hir::PatExpr<'tcx>>,
) -> Result< ) -> Result<
(Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>), (Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
ErrorGuaranteed, ErrorGuaranteed,
@ -200,13 +200,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// This is only called when the range is already known to be malformed. /// This is only called when the range is already known to be malformed.
fn error_on_literal_overflow( fn error_on_literal_overflow(
&self, &self,
expr: Option<&'tcx hir::Expr<'tcx>>, expr: Option<&'tcx hir::PatExpr<'tcx>>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
use hir::{ExprKind, UnOp};
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
let Some(mut expr) = expr else { let Some(expr) = expr else {
return Ok(()); return Ok(());
}; };
let span = expr.span; let span = expr.span;
@ -214,12 +213,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// We need to inspect the original expression, because if we only inspect the output of // We need to inspect the original expression, because if we only inspect the output of
// `eval_bits`, an overflowed value has already been wrapped around. // `eval_bits`, an overflowed value has already been wrapped around.
// We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint. // We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint.
let mut negated = false; let hir::PatExprKind::Lit { lit, negated } = expr.kind else {
if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind {
negated = true;
expr = sub_expr;
}
let ExprKind::Lit(lit) = expr.kind else {
return Ok(()); return Ok(());
}; };
let LitKind::Int(lit_val, _) = lit.node else { let LitKind::Int(lit_val, _) = lit.node else {
@ -248,8 +242,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern_range( fn lower_pattern_range(
&mut self, &mut self,
lo_expr: Option<&'tcx hir::Expr<'tcx>>, lo_expr: Option<&'tcx hir::PatExpr<'tcx>>,
hi_expr: Option<&'tcx hir::Expr<'tcx>>, hi_expr: Option<&'tcx hir::PatExpr<'tcx>>,
end: RangeEnd, end: RangeEnd,
ty: Ty<'tcx>, ty: Ty<'tcx>,
span: Span, span: Span,
@ -330,7 +324,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
hir::PatKind::Never => PatKind::Never, hir::PatKind::Never => PatKind::Never,
hir::PatKind::Lit(value) => self.lower_lit(value), hir::PatKind::Expr(value) => self.lower_lit(value),
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
@ -662,25 +656,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// The special case for negation exists to allow things like `-128_i8` /// The special case for negation exists to allow things like `-128_i8`
/// which would overflow if we tried to evaluate `128_i8` and then negate /// which would overflow if we tried to evaluate `128_i8` and then negate
/// afterwards. /// afterwards.
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> { fn lower_lit(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> {
let (lit, neg) = match expr.kind { let (lit, neg) = match &expr.kind {
hir::ExprKind::Path(ref qpath) => { hir::PatExprKind::Path(qpath) => {
return self.lower_path(qpath, expr.hir_id, expr.span).kind; return self.lower_path(qpath, expr.hir_id, expr.span).kind;
} }
hir::ExprKind::ConstBlock(ref anon_const) => { hir::PatExprKind::ConstBlock(anon_const) => {
return self.lower_inline_const(anon_const, expr.hir_id, expr.span); return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
} }
hir::ExprKind::Lit(ref lit) => (lit, false), hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
let hir::ExprKind::Lit(ref lit) = expr.kind else {
span_bug!(expr.span, "not a literal: {:?}", expr);
};
(lit, true)
}
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
}; };
let ct_ty = self.typeck_results.expr_ty(expr); let ct_ty = self.typeck_results.node_type(expr.hir_id);
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
match self.tcx.at(expr.span).lit_to_const(lit_input) { match self.tcx.at(expr.span).lit_to_const(lit_input) {
Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind, Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind,

View file

@ -656,14 +656,14 @@ impl<'a> Parser<'a> {
fn visit_pat(&mut self, p: &'a Pat) -> Self::Result { fn visit_pat(&mut self, p: &'a Pat) -> Self::Result {
match &p.kind { match &p.kind {
// Base expression // Base expression
PatKind::Err(_) | PatKind::Lit(_) => { PatKind::Err(_) | PatKind::Expr(_) => {
self.maybe_add_suggestions_then_emit(p.span, p.span, false) self.maybe_add_suggestions_then_emit(p.span, p.span, false)
} }
// Sub-patterns // Sub-patterns
// FIXME: this doesn't work with recursive subpats (`&mut &mut <err>`) // FIXME: this doesn't work with recursive subpats (`&mut &mut <err>`)
PatKind::Box(subpat) | PatKind::Ref(subpat, _) PatKind::Box(subpat) | PatKind::Ref(subpat, _)
if matches!(subpat.kind, PatKind::Err(_) | PatKind::Lit(_)) => if matches!(subpat.kind, PatKind::Err(_) | PatKind::Expr(_)) =>
{ {
self.maybe_add_suggestions_then_emit(subpat.span, p.span, false) self.maybe_add_suggestions_then_emit(subpat.span, p.span, false)
} }
@ -766,7 +766,7 @@ impl<'a> Parser<'a> {
if let Some(re) = self.parse_range_end() { if let Some(re) = self.parse_range_end() {
self.parse_pat_range_begin_with(const_expr, re)? self.parse_pat_range_begin_with(const_expr, re)?
} else { } else {
PatKind::Lit(const_expr) PatKind::Expr(const_expr)
} }
} else if self.is_builtin() { } else if self.is_builtin() {
self.parse_pat_builtin()? self.parse_pat_builtin()?
@ -833,7 +833,7 @@ impl<'a> Parser<'a> {
.struct_span_err(self_.token.span, msg) .struct_span_err(self_.token.span, msg)
.with_span_label(self_.token.span, format!("expected {expected}")) .with_span_label(self_.token.span, format!("expected {expected}"))
}); });
PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit))) PatKind::Expr(self.mk_expr(lo, ExprKind::Lit(lit)))
} else { } else {
// Try to parse everything else as literal with optional minus // Try to parse everything else as literal with optional minus
match self.parse_literal_maybe_minus() { match self.parse_literal_maybe_minus() {
@ -845,7 +845,7 @@ impl<'a> Parser<'a> {
match self.parse_range_end() { match self.parse_range_end() {
Some(form) => self.parse_pat_range_begin_with(begin, form)?, Some(form) => self.parse_pat_range_begin_with(begin, form)?,
None => PatKind::Lit(begin), None => PatKind::Expr(begin),
} }
} }
Err(err) => return self.fatal_unexpected_non_pat(err, expected), Err(err) => return self.fatal_unexpected_non_pat(err, expected),
@ -989,7 +989,7 @@ impl<'a> Parser<'a> {
match &pat.kind { match &pat.kind {
// recover ranges with parentheses around the `(start)..` // recover ranges with parentheses around the `(start)..`
PatKind::Lit(begin) PatKind::Expr(begin)
if self.may_recover() if self.may_recover()
&& let Some(form) = self.parse_range_end() => && let Some(form) = self.parse_range_end() =>
{ {

View file

@ -304,7 +304,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
Box, Box,
Deref, Deref,
Ref, Ref,
Lit, Expr,
Guard, Guard,
Range, Range,
Slice, Slice,
@ -587,7 +587,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
Box, Box,
Deref, Deref,
Ref, Ref,
Lit, Expr,
Range, Range,
Slice, Slice,
Rest, Rest,

View file

@ -1130,7 +1130,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
let None = following_seg else { return }; let None = following_seg else { return };
for rib in self.ribs[ValueNS].iter().rev() { for rib in self.ribs[ValueNS].iter().rev() {
for (def_id, spans) in &rib.patterns_with_skipped_bindings { for (def_id, spans) in &rib.patterns_with_skipped_bindings {
if let Some(fields) = self.r.field_idents(*def_id) { if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id)
&& let Some(fields) = self.r.field_idents(*def_id)
{
for field in fields { for field in fields {
if field.name == segment.ident.name { if field.name == segment.ident.name {
if spans.iter().all(|(_, had_error)| had_error.is_err()) { if spans.iter().all(|(_, had_error)| had_error.is_err()) {

View file

@ -1592,15 +1592,9 @@ impl Step for Extended {
prepare("cargo"); prepare("cargo");
prepare("rust-std"); prepare("rust-std");
prepare("rust-analysis"); prepare("rust-analysis");
prepare("clippy");
for tool in &[ prepare("rust-analyzer");
"clippy", for tool in &["rust-docs", "miri", "rustc-codegen-cranelift"] {
"rustfmt",
"rust-analyzer",
"rust-docs",
"miri",
"rustc-codegen-cranelift",
] {
if built_tools.contains(tool) { if built_tools.contains(tool) {
prepare(tool); prepare(tool);
} }
@ -1640,8 +1634,6 @@ impl Step for Extended {
"rust-analyzer-preview".to_string() "rust-analyzer-preview".to_string()
} else if name == "clippy" { } else if name == "clippy" {
"clippy-preview".to_string() "clippy-preview".to_string()
} else if name == "rustfmt" {
"rustfmt-preview".to_string()
} else if name == "miri" { } else if name == "miri" {
"miri-preview".to_string() "miri-preview".to_string()
} else if name == "rustc-codegen-cranelift" { } else if name == "rustc-codegen-cranelift" {
@ -1661,7 +1653,7 @@ impl Step for Extended {
prepare("cargo"); prepare("cargo");
prepare("rust-analysis"); prepare("rust-analysis");
prepare("rust-std"); prepare("rust-std");
for tool in &["clippy", "rustfmt", "rust-analyzer", "rust-docs", "miri"] { for tool in &["clippy", "rust-analyzer", "rust-docs", "miri"] {
if built_tools.contains(tool) { if built_tools.contains(tool) {
prepare(tool); prepare(tool);
} }
@ -1779,24 +1771,6 @@ impl Step for Extended {
.arg(etc.join("msi/remove-duplicates.xsl")) .arg(etc.join("msi/remove-duplicates.xsl"))
.run(builder); .run(builder);
} }
if built_tools.contains("rustfmt") {
command(&heat)
.current_dir(&exe)
.arg("dir")
.arg("rustfmt")
.args(heat_flags)
.arg("-cg")
.arg("RustFmtGroup")
.arg("-dr")
.arg("RustFmt")
.arg("-var")
.arg("var.RustFmtDir")
.arg("-out")
.arg(exe.join("RustFmtGroup.wxs"))
.arg("-t")
.arg(etc.join("msi/remove-duplicates.xsl"))
.run(builder);
}
if built_tools.contains("miri") { if built_tools.contains("miri") {
command(&heat) command(&heat)
.current_dir(&exe) .current_dir(&exe)
@ -1868,9 +1842,6 @@ impl Step for Extended {
if built_tools.contains("clippy") { if built_tools.contains("clippy") {
cmd.arg("-dClippyDir=clippy"); cmd.arg("-dClippyDir=clippy");
} }
if built_tools.contains("rustfmt") {
cmd.arg("-dRustFmtDir=rustfmt");
}
if built_tools.contains("rust-docs") { if built_tools.contains("rust-docs") {
cmd.arg("-dDocsDir=rust-docs"); cmd.arg("-dDocsDir=rust-docs");
} }
@ -1897,9 +1868,6 @@ impl Step for Extended {
if built_tools.contains("clippy") { if built_tools.contains("clippy") {
candle("ClippyGroup.wxs".as_ref()); candle("ClippyGroup.wxs".as_ref());
} }
if built_tools.contains("rustfmt") {
candle("RustFmtGroup.wxs".as_ref());
}
if built_tools.contains("miri") { if built_tools.contains("miri") {
candle("MiriGroup.wxs".as_ref()); candle("MiriGroup.wxs".as_ref());
} }
@ -1938,9 +1906,6 @@ impl Step for Extended {
if built_tools.contains("clippy") { if built_tools.contains("clippy") {
cmd.arg("ClippyGroup.wixobj"); cmd.arg("ClippyGroup.wixobj");
} }
if built_tools.contains("rustfmt") {
cmd.arg("RustFmtGroup.wixobj");
}
if built_tools.contains("miri") { if built_tools.contains("miri") {
cmd.arg("MiriGroup.wixobj"); cmd.arg("MiriGroup.wixobj");
} }

View file

@ -172,11 +172,6 @@
<!-- tool-rust-docs-end --> <!-- tool-rust-docs-end -->
<Directory Id="Cargo" Name="." /> <Directory Id="Cargo" Name="." />
<Directory Id="Std" Name="." /> <Directory Id="Std" Name="." />
<Directory Id="RustFmt" Name="." />
<Directory Id="RustAnalyzer" Name="." />
<Directory Id="Miri" Name="." />
<Directory Id="Analysis" Name="." />
<Directory Id="Clippy" Name="." />
</Directory> </Directory>
</Directory> </Directory>
@ -284,41 +279,7 @@
<ComponentRef Id="PathEnvPerMachine" /> <ComponentRef Id="PathEnvPerMachine" />
<ComponentRef Id="PathEnvPerUser" /> <ComponentRef Id="PathEnvPerUser" />
</Feature> </Feature>
<Feature Id="RustFmt"
Title="Formatter for rust"
Display="7"
Level="1"
AllowAdvertise="no">
<ComponentGroupRef Id="RustFmtGroup" />
</Feature>
<Feature Id="Clippy"
Title="Formatter and checker for rust"
Display="8"
Level="1"
AllowAdvertise="no">
<ComponentGroupRef Id="ClippyGroup" />
</Feature>
<Feature Id="Miri"
Title="Soundness checker for rust"
Display="9"
Level="1"
AllowAdvertise="no">
<ComponentGroupRef Id="MiriGroup" />
</Feature>
<Feature Id="RustAnalyzer"
Title="Analyzer for rust"
Display="10"
Level="1"
AllowAdvertise="no">
<ComponentGroupRef Id="RustAnalyzerGroup" />
</Feature>
<Feature Id="Analysis"
Title="Analysis for rust"
Display="11"
Level="1"
AllowAdvertise="no">
<ComponentGroupRef Id="AnalysisGroup" />
</Feature>
<UIRef Id="RustUI" /> <UIRef Id="RustUI" />
</Product> </Product>
</Wix> </Wix>

View file

@ -314,9 +314,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
PatKind::Box(p) => return name_from_pat(p), PatKind::Box(p) => return name_from_pat(p),
PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)), PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)),
PatKind::Ref(p, _) => return name_from_pat(p), PatKind::Ref(p, _) => return name_from_pat(p),
PatKind::Lit(..) => { PatKind::Expr(..) => {
warn!( warn!(
"tried to get argument name from PatKind::Lit, which is silly in function arguments" "tried to get argument name from PatKind::Expr, which is silly in function arguments"
); );
return Symbol::intern("()"); return Symbol::intern("()");
} }

View file

@ -3,8 +3,11 @@ use clippy_utils::numeric_literal;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt}; use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat, walk_stmt};
use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind, StructTailExpr}; use rustc_hir::{
Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Pat, PatExpr, PatExprKind, PatKind, Stmt, StmtKind,
StructTailExpr,
};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
@ -219,6 +222,22 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
walk_expr(self, expr); walk_expr(self, expr);
} }
fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
match pat.kind {
PatKind::Expr(&PatExpr {
hir_id,
kind: PatExprKind::Lit { lit, .. },
..
}) => {
let ty = self.cx.typeck_results().node_type(hir_id);
self.check_lit(lit, ty, hir_id);
return;
},
_ => {},
}
walk_pat(self, pat)
}
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
match stmt.kind { match stmt.kind {
// we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric` // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`

View file

@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
PatKind::Path(_) | PatKind::Lit(_) => true, PatKind::Path(_) | PatKind::Expr(_) => true,
} }
} }

View file

@ -8,8 +8,8 @@ use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::{ use rustc_hir::{
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath, ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy,
TraitItemRef, TyKind, QPath, TraitItemRef, TyKind,
}; };
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@ -163,7 +163,13 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
if let ExprKind::Let(lt) = expr.kind if let ExprKind::Let(lt) = expr.kind
&& match lt.pat.kind { && match lt.pat.kind {
PatKind::Slice([], None, []) => true, PatKind::Slice([], None, []) => true,
PatKind::Lit(lit) if is_empty_string(lit) => true, PatKind::Expr(lit) => match lit.kind {
PatExprKind::Lit { lit, .. } => match lit.node {
LitKind::Str(lit, _) => lit.as_str().is_empty(),
_ => false,
},
_ => false,
},
_ => false, _ => false,
} }
&& !expr.span.from_expansion() && !expr.span.from_expansion()

View file

@ -7,7 +7,7 @@ use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operator
use rustc_ast::LitKind::{Byte, Char}; use rustc_ast::LitKind::{Byte, Char};
use rustc_ast::ast::RangeLimits; use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd}; use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd, PatExpr, PatExprKind, Lit};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
{ {
let arg = peel_ref_operators(cx, arg); let arg = peel_ref_operators(cx, arg);
let ty_sugg = get_ty_sugg(cx, arg, start); let ty_sugg = get_ty_sugg(cx, arg, start);
let range = check_range(start, end); let range = check_expr_range(start, end);
check_is_ascii(cx, expr.span, arg, &range, ty_sugg); check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
} }
} }
@ -196,19 +196,34 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
} }
} }
fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
if let ExprKind::Lit(start_lit) = &start.kind if let ExprKind::Lit(start_lit) = &start.kind
&& let ExprKind::Lit(end_lit) = &end.kind && let ExprKind::Lit(end_lit) = &end.kind
{ {
match (&start_lit.node, &end_lit.node) { check_lit_range(start_lit, end_lit)
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
(Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
(Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
_ => CharRange::Otherwise,
}
} else { } else {
CharRange::Otherwise 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,
(Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
(Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
_ => CharRange::Otherwise,
}
}

View file

@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt;
use rustc_ast::LitKind; use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; use rustc_hir::{PatExpr, PatExprKind, PatKind, RangeEnd};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
@ -38,14 +38,13 @@ declare_clippy_lint! {
} }
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]); declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> { fn expr_as_i128(expr: &PatExpr<'_>) -> Option<i128> {
if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind { if let PatExprKind::Lit { lit, negated } = expr.kind
expr_as_i128(expr).map(|num| -num)
} else if let ExprKind::Lit(lit) = expr.kind
&& let LitKind::Int(num, _) = lit.node && let LitKind::Int(num, _) = lit.node
{ {
// Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now. // Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now.
num.get().try_into().ok() let n = i128::try_from(num.get()).ok()?;
Some(if negated { -n } else { n })
} else { } else {
None None
} }
@ -58,7 +57,7 @@ struct Num {
} }
impl Num { impl Num {
fn new(expr: &Expr<'_>) -> Option<Self> { fn new(expr: &PatExpr<'_>) -> Option<Self> {
Some(Self { Some(Self {
val: expr_as_i128(expr)?, val: expr_as_i128(expr)?,
span: expr.span, span: expr.span,
@ -90,7 +89,7 @@ impl LateLintPass<'_> for ManualRangePatterns {
let mut ranges_found = Vec::new(); let mut ranges_found = Vec::new();
for pat in pats { for pat in pats {
if let PatKind::Lit(lit) = pat.kind if let PatKind::Expr(lit) = pat.kind
&& let Some(num) = Num::new(lit) && let Some(num) = Num::new(lit)
{ {
numbers_found.insert(num.val); numbers_found.insert(num.val);

View file

@ -4,7 +4,7 @@ use clippy_utils::source::{expr_block, snippet};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use rustc_ast::LitKind; use rustc_ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Arm, Expr, ExprKind, PatKind}; use rustc_hir::{Arm, Expr, PatExprKind, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
@ -21,8 +21,8 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
move |diag| { move |diag| {
if arms.len() == 2 { if arms.len() == 2 {
// no guards // no guards
let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind { let exprs = if let PatKind::Expr(arm_bool) = arms[0].pat.kind {
if let ExprKind::Lit(lit) = arm_bool.kind { if let PatExprKind::Lit { lit, .. } = arm_bool.kind {
match lit.node { match lit.node {
LitKind::Bool(true) => Some((arms[0].body, arms[1].body)), LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
LitKind::Bool(false) => Some((arms[1].body, arms[0].body)), LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),

View file

@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd}; use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExprKind, PatKind, RangeEnd};
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty; use rustc_middle::ty;
@ -311,9 +311,9 @@ impl<'a> NormalizedPat<'a> {
); );
Self::Tuple(None, pats) Self::Tuple(None, pats)
}, },
PatKind::Lit(e) => match &e.kind { PatKind::Expr(e) => match &e.kind {
// TODO: Handle negative integers. They're currently treated as a wild match. // TODO: Handle negative integers. They're currently treated as a wild match.
ExprKind::Lit(lit) => match lit.node { PatExprKind::Lit { lit, negated: false } => match lit.node {
LitKind::Str(sym, _) => Self::LitStr(sym), LitKind::Str(sym, _) => Self::LitStr(sym),
LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
LitKind::Byte(val) => Self::LitInt(val.into()), LitKind::Byte(val) => Self::LitInt(val.into()),
@ -330,7 +330,7 @@ impl<'a> NormalizedPat<'a> {
let start = match start { let start = match start {
None => 0, None => 0,
Some(e) => match &e.kind { Some(e) => match &e.kind {
ExprKind::Lit(lit) => match lit.node { PatExprKind::Lit { lit, negated: false } => match lit.node {
LitKind::Int(val, _) => val.get(), LitKind::Int(val, _) => val.get(),
LitKind::Char(val) => val.into(), LitKind::Char(val) => val.into(),
LitKind::Byte(val) => val.into(), LitKind::Byte(val) => val.into(),
@ -342,7 +342,7 @@ impl<'a> NormalizedPat<'a> {
let (end, bounds) = match end { let (end, bounds) = match end {
None => (u128::MAX, RangeEnd::Included), None => (u128::MAX, RangeEnd::Included),
Some(e) => match &e.kind { Some(e) => match &e.kind {
ExprKind::Lit(lit) => match lit.node { PatExprKind::Lit { lit, negated: false } => match lit.node {
LitKind::Int(val, _) => (val.get(), bounds), LitKind::Int(val, _) => (val.get(), bounds),
LitKind::Char(val) => (val.into(), bounds), LitKind::Char(val) => (val.into(), bounds),
LitKind::Byte(val) => (val.into(), bounds), LitKind::Byte(val) => (val.into(), bounds),

View file

@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_lang_item;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::intravisit::{Visitor, walk_expr};
use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind}; use rustc_hir::{Arm, Expr, ExprKind, PatExpr, PatExprKind, LangItem, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::Span; use rustc_span::Span;
@ -85,8 +85,8 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
}; };
for arm in arms { for arm in arms {
if let PatKind::Lit(Expr { if let PatKind::Expr(PatExpr {
kind: ExprKind::Lit(lit), kind: PatExprKind::Lit { lit, negated: false },
.. ..
}) = arm.pat.kind }) = arm.pat.kind
&& let LitKind::Str(symbol, _) = lit.node && let LitKind::Str(symbol, _) = lit.node

View file

@ -8,7 +8,7 @@ use clippy_utils::{
}; };
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone; use rustc_hir::LangItem::OptionNone;
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatKind, Path, QPath}; use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::sym; use rustc_span::sym;
@ -133,7 +133,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
}, },
// compare match_expr ty with RetTy in `fn foo() -> RetTy` // compare match_expr ty with RetTy in `fn foo() -> RetTy`
Node::Item(item) => { Node::Item(item) => {
if let ItemKind::Fn{ .. } = item.kind { if let ItemKind::Fn { .. } = item.kind {
let output = cx let output = cx
.tcx .tcx
.fn_sig(item.owner_id) .fn_sig(item.owner_id)
@ -189,8 +189,12 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
}); });
}, },
// Example: `5 => 5` // Example: `5 => 5`
(PatKind::Lit(pat_lit_expr), ExprKind::Lit(expr_spanned)) => { (PatKind::Expr(pat_expr_expr), ExprKind::Lit(expr_spanned)) => {
if let ExprKind::Lit(pat_spanned) = &pat_lit_expr.kind { if let PatExprKind::Lit {
lit: pat_spanned,
negated: false,
} = &pat_expr_expr.kind
{
return pat_spanned.node == expr_spanned.node; return pat_spanned.node == expr_spanned.node;
} }
}, },

View file

@ -34,13 +34,13 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
if let Arm { pat, guard: None, .. } = *arm { if let Arm { pat, guard: None, .. } = *arm {
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
let lhs_const = if let Some(lhs) = lhs { let lhs_const = if let Some(lhs) = lhs {
ConstEvalCtxt::new(cx).eval(lhs)? ConstEvalCtxt::new(cx).eval_pat_expr(lhs)?
} else { } else {
let min_val_const = ty.numeric_min_val(cx.tcx)?; let min_val_const = ty.numeric_min_val(cx.tcx)?;
mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))? mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
}; };
let rhs_const = if let Some(rhs) = rhs { let rhs_const = if let Some(rhs) = rhs {
ConstEvalCtxt::new(cx).eval(rhs)? ConstEvalCtxt::new(cx).eval_pat_expr(rhs)?
} else { } else {
let max_val_const = ty.numeric_max_val(cx.tcx)?; let max_val_const = ty.numeric_max_val(cx.tcx)?;
mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))? mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
@ -57,8 +57,10 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
}); });
} }
if let PatKind::Lit(value) = pat.kind { if let PatKind::Expr(value) = pat.kind {
let value = ConstEvalCtxt::new(cx).eval_full_int(value)?; let value = ConstEvalCtxt::new(cx)
.eval_pat_expr(value)?
.int_value(cx.tcx, cx.typeck_results().node_type(pat.hir_id))?;
return Some(SpannedRange { return Some(SpannedRange {
span: pat.span, span: pat.span,
node: (value, EndBound::Included(value)), node: (value, EndBound::Included(value)),

View file

@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExprKind, PatKind, QPath, UnOp};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_middle::ty::{self, GenericArgKind, Ty};
use rustc_span::{Span, Symbol, sym}; use rustc_span::{Span, Symbol, sym};
@ -74,8 +74,8 @@ fn find_match_true<'tcx>(
span: Span, span: Span,
message: &'static str, message: &'static str,
) { ) {
if let PatKind::Lit(lit) = pat.kind if let PatKind::Expr(lit) = pat.kind
&& let ExprKind::Lit(lit) = lit.kind && let PatExprKind::Lit { lit, negated: false } = lit.kind
&& let LitKind::Bool(pat_is_true) = lit.node && let LitKind::Bool(pat_is_true) = lit.node
{ {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;

View file

@ -9,7 +9,7 @@ use rustc_arena::DroplessArena;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{Visitor, walk_pat}; use rustc_hir::intravisit::{Visitor, walk_pat};
use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind}; use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, StmtKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef}; use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef};
use rustc_span::{Span, sym}; use rustc_span::{Span, sym};
@ -114,7 +114,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
} }
let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat); let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind let (msg, sugg) = if let PatKind::Path(_) | PatKind::Expr(_) = pat.kind
&& let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex)) && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
&& let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait() && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
&& let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait() && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
@ -126,8 +126,8 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
// scrutinee derives PartialEq and the pattern is a constant. // scrutinee derives PartialEq and the pattern is a constant.
let pat_ref_count = match pat.kind { let pat_ref_count = match pat.kind {
// string literals are already a reference. // string literals are already a reference.
PatKind::Lit(Expr { PatKind::Expr(PatExpr {
kind: ExprKind::Lit(lit), kind: PatExprKind::Lit { lit, negated: false },
.. ..
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1, }) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
_ => pat_ref_count, _ => pat_ref_count,
@ -384,7 +384,7 @@ impl<'a> PatState<'a> {
PatKind::Wild PatKind::Wild
| PatKind::Binding(_, _, _, None) | PatKind::Binding(_, _, _, None)
| PatKind::Lit(_) | PatKind::Expr(_)
| PatKind::Range(..) | PatKind::Range(..)
| PatKind::Path(_) | PatKind::Path(_)
| PatKind::Never | PatKind::Never

View file

@ -11,7 +11,7 @@ use clippy_utils::visitors::{Descend, for_each_expr};
use itertools::Itertools; use itertools::Itertools;
use rustc_ast::{BinOpKind, LitKind}; use rustc_ast::{BinOpKind, LitKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
return ControlFlow::Break(()); return ControlFlow::Break(());
} }
if arm.pat.walk_short(|pat| match pat.kind { if arm.pat.walk_short(|pat| match pat.kind {
PatKind::Lit(expr) if let ExprKind::Lit(lit) = expr.kind => { PatKind::Expr(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => {
if let LitKind::Char(_) = lit.node { if let LitKind::Char(_) = lit.node {
set_char_spans.push(lit.span); set_char_spans.push(lit.span);
} }

View file

@ -92,7 +92,7 @@ impl EarlyLintPass for UnnestedOrPatterns {
} }
fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) { fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
if let Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind { if let Ident(.., None) | Expr(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind {
// This is a leaf pattern, so cloning is unprofitable. // This is a leaf pattern, so cloning is unprofitable.
return; return;
} }
@ -228,7 +228,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
// Therefore they are not some form of constructor `C`, // Therefore they are not some form of constructor `C`,
// with which a pattern `C(p_0)` may be formed, // with which a pattern `C(p_0)` may be formed,
// which we would want to join with other `C(p_j)`s. // which we would want to join with other `C(p_j)`s.
Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_) Ident(.., None) | Expr(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_)
// Skip immutable refs, as grouping them saves few characters, // Skip immutable refs, as grouping them saves few characters,
// and almost always requires adding parens (increasing noisiness). // and almost always requires adding parens (increasing noisiness).
// In the case of only two patterns, replacement adds net characters. // In the case of only two patterns, replacement adds net characters.

View file

@ -4,7 +4,7 @@ use rustc_ast::ast::{LitFloatType, LitKind};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{ use rustc_hir::{
self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind,
FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, StructTailExpr, TyKind, FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, TyKind,
}; };
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
@ -643,6 +643,27 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.expr(expr); self.expr(expr);
} }
fn pat_expr(&self, lit: &Binding<&hir::PatExpr<'_>>) {
let kind = |kind| chain!(self, "let PatExprKind::{kind} = {lit}.kind");
macro_rules! kind {
($($t:tt)*) => (kind(format_args!($($t)*)));
}
match lit.value.kind {
PatExprKind::Lit { lit, negated } => {
bind!(self, lit);
bind!(self, negated);
kind!("Lit{{ref {lit}, {negated} }}");
self.lit(lit);
},
PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"),
PatExprKind::Path(ref qpath) => {
bind!(self, qpath);
kind!("Path(ref {qpath})");
self.qpath(qpath);
},
}
}
fn pat(&self, pat: &Binding<&hir::Pat<'_>>) { fn pat(&self, pat: &Binding<&hir::Pat<'_>>) {
let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind"); let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind");
macro_rules! kind { macro_rules! kind {
@ -717,17 +738,17 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
kind!("Guard({pat}, {cond})"); kind!("Guard({pat}, {cond})");
self.pat(pat); self.pat(pat);
self.expr(cond); self.expr(cond);
} },
PatKind::Lit(lit_expr) => { PatKind::Expr(lit_expr) => {
bind!(self, lit_expr); bind!(self, lit_expr);
kind!("Lit({lit_expr})"); kind!("Expr({lit_expr})");
self.expr(lit_expr); self.pat_expr(lit_expr);
}, },
PatKind::Range(start, end, end_kind) => { PatKind::Range(start, end, end_kind) => {
opt_bind!(self, start, end); opt_bind!(self, start, end);
kind!("Range({start}, {end}, RangeEnd::{end_kind:?})"); kind!("Range({start}, {end}, RangeEnd::{end_kind:?})");
start.if_some(|e| self.expr(e)); start.if_some(|e| self.pat_expr(e));
end.if_some(|e| self.expr(e)); end.if_some(|e| self.pat_expr(e));
}, },
PatKind::Slice(start, middle, end) => { PatKind::Slice(start, middle, end) => {
bind!(self, start, end); bind!(self, start, end);

View file

@ -36,7 +36,7 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
(Paren(l), _) => eq_pat(l, r), (Paren(l), _) => eq_pat(l, r),
(_, Paren(r)) => eq_pat(l, r), (_, Paren(r)) => eq_pat(l, r),
(Wild, Wild) | (Rest, Rest) => true, (Wild, Wild) | (Rest, Rest) => true,
(Lit(l), Lit(r)) => eq_expr(l, r), (Expr(l), Expr(r)) => eq_expr(l, r),
(Ident(b1, i1, s1), Ident(b2, i2, s2)) => { (Ident(b1, i1, s1), Ident(b2, i2, s2)) => {
b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat) b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat)
}, },

View file

@ -4,7 +4,6 @@
//! executable MIR bodies, so we have to do this instead. //! executable MIR bodies, so we have to do this instead.
#![allow(clippy::float_cmp)] #![allow(clippy::float_cmp)]
use crate::macros::HirNode;
use crate::source::{SpanRangeExt, walk_span_to_context}; use crate::source::{SpanRangeExt, walk_span_to_context};
use crate::{clip, is_direct_expn_of, sext, unsext}; use crate::{clip, is_direct_expn_of, sext, unsext};
@ -13,7 +12,7 @@ use rustc_apfloat::ieee::{Half, Quad};
use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_ast::ast::{self, LitFloatType, LitKind};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp, PatExpr, PatExprKind};
use rustc_lexer::tokenize; use rustc_lexer::tokenize;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::mir::ConstValue; use rustc_middle::mir::ConstValue;
@ -442,30 +441,48 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
} }
} }
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, 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(
if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
ConstantSource::CoreConstant
} else {
ConstantSource::Constant
},
);
Some(result)
})
}
/// Simple constant folding: Insert an expression, get a constant or none. /// Simple constant folding: Insert an expression, get a constant or none.
fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> { fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
match e.kind { match e.kind {
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value), ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
ExprKind::DropTemps(e) => self.expr(e), ExprKind::DropTemps(e) => self.expr(e),
ExprKind::Path(ref qpath) => { ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id),
let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.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| {
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(
if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
ConstantSource::CoreConstant
} else {
ConstantSource::Constant
},
);
Some(result)
})
},
ExprKind::Block(block, _) => self.block(block), ExprKind::Block(block, _) => self.block(block),
ExprKind::Lit(lit) => { ExprKind::Lit(lit) => {
if is_direct_expn_of(e.span, "cfg").is_some() { if is_direct_expn_of(e.span, "cfg").is_some() {

View file

@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{ use rustc_hir::{
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
TyKind, TraitBoundModifiers, Ty, TyKind,
}; };
use rustc_lexer::{TokenKind, tokenize}; use rustc_lexer::{TokenKind, tokenize};
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -489,6 +489,24 @@ impl HirEqInterExpr<'_, '_, '_> {
li.name == ri.name && self.eq_pat(lp, rp) li.name == ri.name && self.eq_pat(lp, rp)
} }
fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool {
match (&left.kind, &right.kind) {
(
&PatExprKind::Lit {
lit: left,
negated: left_neg,
},
&PatExprKind::Lit {
lit: right,
negated: right_neg,
},
) => left_neg == right_neg && left.node == right.node,
(PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body),
(PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right),
(PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false,
}
}
/// Checks whether two patterns are the same. /// Checks whether two patterns are the same.
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool { fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
match (&left.kind, &right.kind) { match (&left.kind, &right.kind) {
@ -507,11 +525,11 @@ impl HirEqInterExpr<'_, '_, '_> {
eq eq
}, },
(PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r), (PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
(&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r), (&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r),
(&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)), (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
(&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => { (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_expr(a, b)) both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_pat_expr(a, b))
&& both(le.as_ref(), re.as_ref(), |a, b| self.eq_expr(a, b)) && both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b))
&& (li == ri) && (li == ri)
}, },
(&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re), (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
@ -1073,6 +1091,18 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s); // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
} }
pub fn hash_pat_expr(&mut self, lit: &PatExpr<'_>) {
std::mem::discriminant(&lit.kind).hash(&mut self.s);
match &lit.kind {
PatExprKind::Lit { lit, negated } => {
lit.node.hash(&mut self.s);
negated.hash(&mut self.s);
},
PatExprKind::ConstBlock(c) => self.hash_body(c.body),
PatExprKind::Path(qpath) => self.hash_qpath(qpath),
}
}
pub fn hash_pat(&mut self, pat: &Pat<'_>) { pub fn hash_pat(&mut self, pat: &Pat<'_>) {
std::mem::discriminant(&pat.kind).hash(&mut self.s); std::mem::discriminant(&pat.kind).hash(&mut self.s);
match pat.kind { match pat.kind {
@ -1084,7 +1114,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
} }
}, },
PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat), PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat),
PatKind::Lit(expr) => self.hash_expr(expr), PatKind::Expr(expr) => self.hash_pat_expr(expr),
PatKind::Or(pats) => { PatKind::Or(pats) => {
for pat in pats { for pat in pats {
self.hash_pat(pat); self.hash_pat(pat);
@ -1093,10 +1123,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
PatKind::Path(ref qpath) => self.hash_qpath(qpath), PatKind::Path(ref qpath) => self.hash_qpath(qpath),
PatKind::Range(s, e, i) => { PatKind::Range(s, e, i) => {
if let Some(s) = s { if let Some(s) = s {
self.hash_expr(s); self.hash_pat_expr(s);
} }
if let Some(e) = e { if let Some(e) = e {
self.hash_expr(e); self.hash_pat_expr(e);
} }
std::mem::discriminant(&i).hash(&mut self.s); std::mem::discriminant(&i).hash(&mut self.s);
}, },

View file

@ -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,
} }
} }

View file

@ -30,8 +30,8 @@ if let StmtKind::Let(local) = stmt.kind
} }
if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind
&& let ExprKind::Let(let_expr) = cond.kind && let ExprKind::Let(let_expr) = cond.kind
&& let PatKind::Lit(lit_expr) = let_expr.pat.kind && let PatKind::Expr(lit_expr) = let_expr.pat.kind
&& let ExprKind::Lit(ref lit) = lit_expr.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
&& let LitKind::Bool(true) = lit.node && let LitKind::Bool(true) = lit.node
&& let ExprKind::Path(ref qpath) = let_expr.init.kind && let ExprKind::Path(ref qpath) = let_expr.init.kind
&& match_qpath(qpath, &["a"]) && match_qpath(qpath, &["a"])

View file

@ -76,8 +76,8 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While:
// report your lint here // report your lint here
} }
if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr) if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr)
&& let PatKind::Lit(lit_expr) = let_pat.kind && let PatKind::Expr(lit_expr) = let_pat.kind
&& let ExprKind::Lit(ref lit) = lit_expr.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
&& let LitKind::Bool(true) = lit.node && let LitKind::Bool(true) = lit.node
&& let ExprKind::Path(ref qpath) = let_expr.kind && let ExprKind::Path(ref qpath) = let_expr.kind
&& match_qpath(qpath, &["a"]) && match_qpath(qpath, &["a"])

View file

@ -4,14 +4,14 @@ if let StmtKind::Let(local) = stmt.kind
&& let ExprKind::Lit(ref lit) = scrutinee.kind && let ExprKind::Lit(ref lit) = scrutinee.kind
&& let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
&& arms.len() == 3 && arms.len() == 3
&& let PatKind::Lit(lit_expr) = arms[0].pat.kind && let PatKind::Expr(lit_expr) = arms[0].pat.kind
&& let ExprKind::Lit(ref lit1) = lit_expr.kind && let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind
&& let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node
&& arms[0].guard.is_none() && arms[0].guard.is_none()
&& let ExprKind::Lit(ref lit2) = arms[0].body.kind && let ExprKind::Lit(ref lit2) = arms[0].body.kind
&& let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
&& let PatKind::Lit(lit_expr1) = arms[1].pat.kind && let PatKind::Expr(lit_expr1) = arms[1].pat.kind
&& let ExprKind::Lit(ref lit3) = lit_expr1.kind && let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind
&& let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node
&& arms[1].guard.is_none() && arms[1].guard.is_none()
&& let ExprKind::Block(block, None) = arms[1].body.kind && let ExprKind::Block(block, None) = arms[1].body.kind

View file

@ -23,8 +23,8 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
&& match_qpath(qpath, &["Test"]) && match_qpath(qpath, &["Test"])
&& fields.len() == 1 && fields.len() == 1
&& fields[0].ident.as_str() == "field" && fields[0].ident.as_str() == "field"
&& let PatKind::Lit(lit_expr) = fields[0].pat.kind && let PatKind::Expr(lit_expr) = fields[0].pat.kind
&& let ExprKind::Lit(ref lit) = lit_expr.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
&& arm.guard.is_none() && arm.guard.is_none()
&& let ExprKind::Block(block, None) = arm.body.kind && let ExprKind::Block(block, None) = arm.body.kind
@ -36,8 +36,8 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind
&& match_qpath(qpath, &["TestTuple"]) && match_qpath(qpath, &["TestTuple"])
&& fields.len() == 1 && fields.len() == 1
&& let PatKind::Lit(lit_expr) = fields[0].kind && let PatKind::Expr(lit_expr) = fields[0].kind
&& let ExprKind::Lit(ref lit) = lit_expr.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
&& arm.guard.is_none() && arm.guard.is_none()
&& let ExprKind::Block(block, None) = arm.body.kind && let ExprKind::Block(block, None) = arm.body.kind

View file

@ -42,7 +42,7 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
| ast::PatKind::Never | ast::PatKind::Never
| ast::PatKind::Wild | ast::PatKind::Wild
| ast::PatKind::Err(_) | ast::PatKind::Err(_)
| ast::PatKind::Lit(_) => true, | ast::PatKind::Expr(_) => true,
ast::PatKind::Ident(_, _, ref pat) => pat.is_none(), ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
ast::PatKind::Struct(..) ast::PatKind::Struct(..)
| ast::PatKind::MacCall(..) | ast::PatKind::MacCall(..)
@ -293,7 +293,7 @@ impl Rewrite for Pat {
let path_str = rewrite_path(context, PathContext::Expr, q_self, path, shape)?; let path_str = rewrite_path(context, PathContext::Expr, q_self, path, shape)?;
rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape) rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
} }
PatKind::Lit(ref expr) => expr.rewrite_result(context, shape), PatKind::Expr(ref expr) => expr.rewrite_result(context, shape),
PatKind::Slice(ref slice_pat) PatKind::Slice(ref slice_pat)
if context.config.style_edition() <= StyleEdition::Edition2021 => if context.config.style_edition() <= StyleEdition::Edition2021 =>
{ {
@ -530,7 +530,7 @@ pub(crate) fn can_be_overflowed_pat(
ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => { ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => {
can_be_overflowed_pat(context, &TuplePatField::Pat(p), len) can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
} }
ast::PatKind::Lit(ref expr) => can_be_overflowed_expr(context, expr, len), ast::PatKind::Expr(ref expr) => can_be_overflowed_expr(context, expr, len),
_ => false, _ => false,
}, },
TuplePatField::Dotdot(..) => false, TuplePatField::Dotdot(..) => false,

View file

@ -569,7 +569,7 @@ fn test_pat() {
c1!(pat, [ &pat ], "&pat"); c1!(pat, [ &pat ], "&pat");
c1!(pat, [ &mut pat ], "&mut pat"); c1!(pat, [ &mut pat ], "&mut pat");
// PatKind::Lit // PatKind::Expr
c1!(pat, [ 1_000_i8 ], "1_000_i8"); c1!(pat, [ 1_000_i8 ], "1_000_i8");
// PatKind::Range // PatKind::Range

View file

@ -6,7 +6,7 @@ macro_rules! enum_number {
fn foo(value: i32) -> Option<$name> { fn foo(value: i32) -> Option<$name> {
match value { match value {
$( $value => Some($name::$variant), )* // PatKind::Lit $( $value => Some($name::$variant), )* // PatKind::Expr
$( $value ..= 42 => Some($name::$variant), )* // PatKind::Range $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range
_ => None _ => None
} }

View file

@ -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
}
}

View file

@ -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`.

View file

@ -3,6 +3,10 @@ struct Website {
title: Option<String>, title: Option<String>,
} }
enum Foo {
Bar { a: i32 },
}
fn main() { fn main() {
let website = Website { let website = Website {
url: "http://www.example.com".into(), url: "http://www.example.com".into(),
@ -18,4 +22,9 @@ fn main() {
println!("[{}]({})", title, url); //~ ERROR cannot find value `title` in this scope println!("[{}]({})", title, url); //~ ERROR cannot find value `title` in this scope
//~^ NOTE not found in this scope //~^ NOTE not found in this scope
} }
let x = Foo::Bar { a: 1 };
if let Foo::Bar { .. } = x { //~ NOTE this pattern
println!("{a}"); //~ ERROR cannot find value `a` in this scope
}
} }

View file

@ -1,5 +1,5 @@
error: expected `,` error: expected `,`
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:12:31 --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:16:31
| |
LL | if let Website { url, Some(title) } = website { LL | if let Website { url, Some(title) } = website {
| ------- ^ | ------- ^
@ -7,13 +7,21 @@ LL | if let Website { url, Some(title) } = website {
| while parsing the fields for this pattern | while parsing the fields for this pattern
error[E0425]: cannot find value `title` in this scope error[E0425]: cannot find value `title` in this scope
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:18:30 --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:22:30
| |
LL | if let Website { url, .. } = website { LL | if let Website { url, .. } = website {
| ------------------- this pattern doesn't include `title`, which is available in `Website` | ------------------- this pattern doesn't include `title`, which is available in `Website`
LL | println!("[{}]({})", title, url); LL | println!("[{}]({})", title, url);
| ^^^^^ not found in this scope | ^^^^^ not found in this scope
error: aborting due to 2 previous errors error[E0425]: cannot find value `a` in this scope
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:28:20
|
LL | if let Foo::Bar { .. } = x {
| --------------- this pattern doesn't include `a`, which is available in `Bar`
LL | println!("{a}");
| ^ help: a local variable with a similar name exists: `x`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0425`. For more information about this error, try `rustc --explain E0425`.

View file

@ -651,8 +651,8 @@ mod patterns {
let &mut pat; let &mut pat;
} }
/// PatKind::Lit /// PatKind::Expr
fn pat_lit() { fn pat_expr() {
let 1_000_i8; let 1_000_i8;
let -""; let -"";
} }

View file

@ -567,8 +567,8 @@ mod patterns {
fn pat_deref() { let deref!(pat); } fn pat_deref() { let deref!(pat); }
/// PatKind::Ref /// PatKind::Ref
fn pat_ref() { let &pat; let &mut pat; } fn pat_ref() { let &pat; let &mut pat; }
/// PatKind::Lit /// PatKind::Expr
fn pat_lit() { let 1_000_i8; let -""; } fn pat_expr() { let 1_000_i8; let -""; }
/// PatKind::Range /// PatKind::Range
fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; } fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; }
/// PatKind::Slice /// PatKind::Slice

View file

@ -14,4 +14,4 @@ extern crate std;
fn main() ({ } as ()) fn main() ({ } as ())
fn foo((-(128 as i8) as i8)...(127 as i8): i8) ({ } as ()) fn foo(-128...127: i8) ({ } as ())

View file

@ -420,13 +420,20 @@ trigger_files = [
[autolabel."A-testsuite"] [autolabel."A-testsuite"]
trigger_files = [ trigger_files = [
"src/bootstrap/src/core/build_steps/test.rs",
"src/ci", "src/ci",
"src/tools/compiletest",
"src/tools/cargotest", "src/tools/cargotest",
"src/tools/tidy", "src/tools/compiletest",
"src/tools/miropt-test-tools",
"src/tools/remote-test-server", "src/tools/remote-test-server",
"src/tools/remote-test-client", "src/tools/remote-test-client",
"src/tools/tier-check" "src/tools/rustdoc-gui-test",
"src/tools/suggest-tests",
]
[autolabel."A-tidy"]
trigger_files = [
"src/tools/tidy",
] ]
[autolabel."A-meta"] [autolabel."A-meta"]