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)
- [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377)
- [Implement `FromStr` for `CString` and `TryFrom<CString>` for `String`](https://github.com/rust-lang/rust/pull/130608)
- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/130635)
- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/123723)
<a id="1.84.0-Stabilized-APIs"></a>

View file

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

View file

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

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));
visit_opt!(visitor, visit_pat, optional_subpattern);
}
PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)),
PatKind::Expr(expression) => try_visit!(visitor.visit_expr(expression)),
PatKind::Range(lower_bound, upper_bound, _end) => {
visit_opt!(visitor, visit_expr, lower_bound);
visit_opt!(visitor, visit_expr, upper_bound);

View file

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

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>) {
self.insert(field.span, field.hir_id, Node::PatField(field));
self.with_parent(field.hir_id, |this| {

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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::Deref(p) => format!("deref!({})", name_from_pat(p)),
PatKind::Ref(p, _) => return name_from_pat(p),
PatKind::Lit(..) => {
PatKind::Expr(..) => {
warn!(
"tried to get argument name from PatKind::Lit, which is silly in function arguments"
"tried to get argument name from PatKind::Expr, which is silly in function arguments"
);
return Symbol::intern("()");
}

View file

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

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::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
PatKind::Path(_) | PatKind::Lit(_) => true,
PatKind::Path(_) | PatKind::Expr(_) => true,
}
}

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,7 +4,6 @@
//! executable MIR bodies, so we have to do this instead.
#![allow(clippy::float_cmp)]
use crate::macros::HirNode;
use crate::source::{SpanRangeExt, walk_span_to_context};
use crate::{clip, is_direct_expn_of, sext, unsext};
@ -13,7 +12,7 @@ use rustc_apfloat::ieee::{Half, Quad};
use rustc_ast::ast::{self, LitFloatType, LitKind};
use rustc_data_structures::sync::Lrc;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp, PatExpr, PatExprKind};
use rustc_lexer::tokenize;
use rustc_lint::LateContext;
use rustc_middle::mir::ConstValue;
@ -442,18 +441,29 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
}
}
/// Simple constant folding: Insert an expression, get a constant or none.
fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
match e.kind {
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
ExprKind::DropTemps(e) => self.expr(e),
ExprKind::Path(ref qpath) => {
let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() {
pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option<Constant<'tcx>> {
match &pat_expr.kind {
PatExprKind::Lit { lit, negated } => {
let ty = self.typeck.node_type_opt(pat_expr.hir_id);
let val = lit_to_mir_constant(&lit.node, ty);
if *negated {
self.constant_negate(&val, ty?)
} else {
Some(val)
}
}
PatExprKind::ConstBlock(ConstBlock { body, ..}) => self.expr(self.tcx.hir().body(*body).value),
PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id),
}
}
fn qpath(&self, qpath: &QPath<'_>, hir_id: HirId) -> Option<Constant<'tcx>> {
let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, hir_id).opt_def_id() {
self.tcx.crate_name(def_id.krate) == sym::core
} else {
false
};
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
self.fetch_path_and_apply(qpath, hir_id, self.typeck.node_type(hir_id), |self_, result| {
let result = mir_to_const(self_.tcx, result)?;
// If source is already Constant we wouldn't want to override it with CoreConstant
self_.source.set(
@ -465,7 +475,14 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
);
Some(result)
})
},
}
/// Simple constant folding: Insert an expression, get a constant or none.
fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
match e.kind {
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
ExprKind::DropTemps(e) => self.expr(e),
ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id),
ExprKind::Block(block, _) => self.block(block),
ExprKind::Lit(lit) => {
if is_direct_expn_of(e.span, "cfg").is_some() {

View file

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

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
&& let ExprKind::Let(let_expr) = cond.kind
&& let PatKind::Lit(lit_expr) = let_expr.pat.kind
&& let ExprKind::Lit(ref lit) = lit_expr.kind
&& let PatKind::Expr(lit_expr) = let_expr.pat.kind
&& let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
&& let LitKind::Bool(true) = lit.node
&& let ExprKind::Path(ref qpath) = let_expr.init.kind
&& match_qpath(qpath, &["a"])

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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