Skip to content

Rollup of 6 pull requests #135218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jan 8, 2025
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions compiler/rustc_ast_lowering/src/pat.rs
Original file line number Diff line number Diff line change
@@ -120,8 +120,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_range_end(end, e2.is_some()),
);
}
// FIXME(guard_patterns): lower pattern guards to HIR
PatKind::Guard(inner, _) => pattern = inner,
PatKind::Guard(inner, cond) => {
break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond));
}
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
PatKind::Rest => {
// If we reach here the `..` pattern is not semantically allowed.
26 changes: 8 additions & 18 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
@@ -978,7 +978,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
) -> bool {
let tcx = infcx.tcx;
let TypeTest { generic_kind, lower_bound, span: blame_span, ref verify_bound } = *type_test;
let TypeTest { generic_kind, lower_bound, span: blame_span, verify_bound: _ } = *type_test;

let generic_ty = generic_kind.to_ty(tcx);
let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else {
@@ -1016,25 +1016,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// For each region outlived by lower_bound find a non-local,
// universal region (it may be the same region) and add it to
// `ClosureOutlivesRequirement`.
let mut found_outlived_universal_region = false;
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
found_outlived_universal_region = true;
debug!("universal_region_outlived_by ur={:?}", ur);
// Check whether we can already prove that the "subject" outlives `ur`.
// If so, we don't have to propagate this requirement to our caller.
//
// To continue the example from the function, if we are trying to promote
// a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union
// `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here
// we check whether `T: '1` is something we *can* prove. If so, no need
// to propagate that requirement.
//
// This is needed because -- particularly in the case
// where `ur` is a local bound -- we are sometimes in a
// position to prove things that our caller cannot. See
// #53570 for an example.
if self.eval_verify_bound(infcx, generic_ty, ur, &verify_bound) {
continue;
}

let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
debug!(?non_local_ub);

@@ -1056,6 +1041,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
propagated_outlives_requirements.push(requirement);
}
}
// If we succeed to promote the subject, i.e. it only contains non-local regions,
// and fail to prove the type test inside of the closure, the `lower_bound` has to
// also be at least as large as some universal region, as the type test is otherwise
// trivial.
assert!(found_outlived_universal_region);
true
}

7 changes: 5 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
@@ -1387,7 +1387,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*;
match self.kind {
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
Slice(before, slice, after) => {
@@ -1414,7 +1414,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*;
match self.kind {
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
Slice(before, slice, after) => {
@@ -1566,6 +1566,9 @@ pub enum PatKind<'hir> {
/// A literal.
Lit(&'hir Expr<'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),

4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
@@ -696,6 +696,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
visit_opt!(visitor, visit_pat, slice_pattern);
walk_list!(visitor, visit_pat, postpatterns);
}
PatKind::Guard(subpat, condition) => {
try_visit!(visitor.visit_pat(subpat));
try_visit!(visitor.visit_expr(condition));
}
}
V::Result::output()
}
5 changes: 4 additions & 1 deletion compiler/rustc_hir_analysis/src/check/region.rs
Original file line number Diff line number Diff line change
@@ -654,6 +654,7 @@ fn resolve_local<'tcx>(
/// | ( ..., P&, ... )
/// | ... "|" P& "|" ...
/// | box P&
/// | P& if ...
/// ```
fn is_binding_pat(pat: &hir::Pat<'_>) -> bool {
// Note that the code below looks for *explicit* refs only, that is, it won't
@@ -694,7 +695,9 @@ fn resolve_local<'tcx>(
| PatKind::TupleStruct(_, subpats, _)
| PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(p)),

PatKind::Box(subpat) | PatKind::Deref(subpat) => is_binding_pat(subpat),
PatKind::Box(subpat) | PatKind::Deref(subpat) | PatKind::Guard(subpat, _) => {
is_binding_pat(subpat)
}

PatKind::Ref(_, _)
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
6 changes: 6 additions & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1999,6 +1999,12 @@ impl<'a> State<'a> {
self.commasep(Inconsistent, after, |s, p| s.print_pat(p));
self.word("]");
}
PatKind::Guard(inner, cond) => {
self.print_pat(inner);
self.space();
self.word_space("if");
self.print_expr(cond);
}
PatKind::Err(_) => {
self.popen();
self.word("/*ERROR*/");
3 changes: 3 additions & 0 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
@@ -456,6 +456,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Does not constitute a read.
hir::PatKind::Wild => false,

// Might not constitute a read, since the condition might be false.
hir::PatKind::Guard(_, _) => true,

// This is unnecessarily restrictive when the pattern that doesn't
// constitute a read is unreachable.
//
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
@@ -615,6 +615,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
| PatKind::Box(_)
| PatKind::Deref(_)
| PatKind::Ref(..)
| PatKind::Guard(..)
| PatKind::Wild
| PatKind::Err(_) => {
// If the PatKind is Or, Box, or Ref, the decision is made later
@@ -1737,7 +1738,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
}
}

PatKind::Binding(.., Some(subpat)) => {
PatKind::Binding(.., Some(subpat)) | PatKind::Guard(subpat, _) => {
self.cat_pattern(place_with_id, subpat, op)?;
}

19 changes: 17 additions & 2 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
@@ -147,8 +147,23 @@ fn typeck_with_fallback<'tcx>(
check_abi(tcx, span, fn_sig.abi());

// Compute the function signature from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
let fn_sig = fcx.normalize(body.value.span, fn_sig);
let mut fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);

// Normalize the input and output types one at a time, using a different
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
// for each type, preventing the HIR wf check from generating
// a nice error message.
let arg_span =
|idx| decl.inputs.get(idx).map_or(decl.output.span(), |arg: &hir::Ty<'_>| arg.span);

fn_sig.inputs_and_output = tcx.mk_type_list_from_iter(
fn_sig
.inputs_and_output
.iter()
.enumerate()
.map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)),
);

check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params());
} else {
10 changes: 9 additions & 1 deletion compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
@@ -284,6 +284,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
}
PatKind::Guard(pat, cond) => {
self.check_pat(pat, expected, pat_info);
self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
expected
}
PatKind::Or(pats) => {
for pat in pats {
self.check_pat(pat, expected, pat_info);
@@ -422,7 +427,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// An OR-pattern just propagates to each individual alternative.
// This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`.
// In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`.
| PatKind::Or(_) => AdjustMode::Pass,
| PatKind::Or(_)
// Like or-patterns, guard patterns just propogate to their subpatterns.
| PatKind::Guard(..) => AdjustMode::Pass,
}
}

@@ -901,6 +908,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PatKind::Struct(..)
| PatKind::TupleStruct(..)
| PatKind::Or(..)
| PatKind::Guard(..)
| PatKind::Tuple(..)
| PatKind::Slice(..) => "binding",

40 changes: 19 additions & 21 deletions compiler/rustc_middle/src/ty/print/mod.rs
Original file line number Diff line number Diff line change
@@ -45,10 +45,25 @@ pub trait Printer<'tcx>: Sized {
&mut self,
impl_def_id: DefId,
args: &'tcx [GenericArg<'tcx>],
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
self.default_print_impl_path(impl_def_id, args, self_ty, trait_ref)
let tcx = self.tcx();
let self_ty = tcx.type_of(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let (self_ty, impl_trait_ref) = if tcx.generics_of(impl_def_id).count() <= args.len() {
(
self_ty.instantiate(tcx, args),
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(tcx, args)),
)
} else {
// We are probably printing a nested item inside of an impl.
// Use the identity substitutions for the impl.
(
self_ty.instantiate_identity(),
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
)
};

self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
}

fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
@@ -107,23 +122,7 @@ pub trait Printer<'tcx>: Sized {
self.path_crate(def_id.krate)
}

DefPathData::Impl => {
let generics = self.tcx().generics_of(def_id);
let self_ty = self.tcx().type_of(def_id);
let impl_trait_ref = self.tcx().impl_trait_ref(def_id);
let (self_ty, impl_trait_ref) = if args.len() >= generics.count() {
(
self_ty.instantiate(self.tcx(), args),
impl_trait_ref.map(|i| i.instantiate(self.tcx(), args)),
)
} else {
(
self_ty.instantiate_identity(),
impl_trait_ref.map(|i| i.instantiate_identity()),
)
};
self.print_impl_path(def_id, args, self_ty, impl_trait_ref)
}
DefPathData::Impl => self.print_impl_path(def_id, args),

_ => {
let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
@@ -201,7 +200,6 @@ pub trait Printer<'tcx>: Sized {
fn default_print_impl_path(
&mut self,
impl_def_id: DefId,
_args: &'tcx [GenericArg<'tcx>],
self_ty: Ty<'tcx>,
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
3 changes: 3 additions & 0 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
@@ -435,6 +435,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {

hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },

// FIXME(guard_patterns): implement guard pattern lowering
hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind,

hir::PatKind::Err(guar) => PatKind::Error(guar),
};

1 change: 1 addition & 0 deletions compiler/rustc_passes/src/input_stats.rs
Original file line number Diff line number Diff line change
@@ -305,6 +305,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
Deref,
Ref,
Lit,
Guard,
Range,
Slice,
Err
29 changes: 21 additions & 8 deletions compiler/rustc_symbol_mangling/src/legacy.rs
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ use rustc_middle::bug;
use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
use rustc_middle::ty::{
self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt,
TypingEnv,
};
use tracing::debug;

@@ -383,14 +384,26 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
&mut self,
impl_def_id: DefId,
args: &'tcx [GenericArg<'tcx>],
mut self_ty: Ty<'tcx>,
mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id);
if !args.is_empty() {
typing_env.param_env =
ty::EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args);
}
let self_ty = self.tcx.type_of(impl_def_id);
let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
let (typing_env, mut self_ty, mut impl_trait_ref) =
if self.tcx.generics_of(impl_def_id).count() <= args.len() {
(
TypingEnv::fully_monomorphized(),
self_ty.instantiate(self.tcx, args),
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
)
} else {
// We are probably printing a nested item inside of an impl.
// Use the identity substitutions for the impl. We also need
// a well-formed param-env, so let's use post-analysis.
(
TypingEnv::post_analysis(self.tcx, impl_def_id),
self_ty.instantiate_identity(),
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
)
};

match &mut impl_trait_ref {
Some(impl_trait_ref) => {
@@ -403,7 +416,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
}
}

self.default_print_impl_path(impl_def_id, args, self_ty, impl_trait_ref)
self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
}
}

30 changes: 21 additions & 9 deletions compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
@@ -14,8 +14,8 @@ use rustc_middle::bug;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::print::{Print, PrintError, Printer};
use rustc_middle::ty::{
self, EarlyBinder, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty,
TyCtxt, TypeVisitable, TypeVisitableExt, UintTy,
self, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty, TyCtxt,
TypeVisitable, TypeVisitableExt, UintTy,
};
use rustc_span::kw;

@@ -227,17 +227,29 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
&mut self,
impl_def_id: DefId,
args: &'tcx [GenericArg<'tcx>],
mut self_ty: Ty<'tcx>,
mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
let key = self.tcx.def_key(impl_def_id);
let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };

let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id);
if !args.is_empty() {
typing_env.param_env =
EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args);
}
let self_ty = self.tcx.type_of(impl_def_id);
let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
let (typing_env, mut self_ty, mut impl_trait_ref) =
if self.tcx.generics_of(impl_def_id).count() <= args.len() {
(
ty::TypingEnv::fully_monomorphized(),
self_ty.instantiate(self.tcx, args),
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
)
} else {
// We are probably printing a nested item inside of an impl.
// Use the identity substitutions for the impl. We also need
// a well-formed param-env, so let's use post-analysis.
(
ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
self_ty.instantiate_identity(),
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
)
};

match &mut impl_trait_ref {
Some(impl_trait_ref) => {
Loading