Skip to content

Commit 21b06c1

Browse files
committed
Auto merge of rust-lang#16131 - HKalbasi:rustc-tests-fixup, r=HKalbasi
Fix false positive type mismatch in const reference patterns
2 parents a776419 + fa5a327 commit 21b06c1

File tree

4 files changed

+97
-46
lines changed

4 files changed

+97
-46
lines changed

crates/hir-ty/src/infer/pat.rs

+22-18
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ impl InferenceContext<'_> {
262262
fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty {
263263
let mut expected = self.resolve_ty_shallow(expected);
264264

265-
if is_non_ref_pat(self.body, pat) {
265+
if self.is_non_ref_pat(self.body, pat) {
266266
let mut pat_adjustments = Vec::new();
267267
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
268268
pat_adjustments.push(expected.clone());
@@ -496,24 +496,28 @@ impl InferenceContext<'_> {
496496

497497
self.infer_expr(expr, &Expectation::has_type(expected.clone()))
498498
}
499-
}
500499

501-
fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
502-
match &body[pat] {
503-
Pat::Tuple { .. }
504-
| Pat::TupleStruct { .. }
505-
| Pat::Record { .. }
506-
| Pat::Range { .. }
507-
| Pat::Slice { .. } => true,
508-
Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)),
509-
// FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
510-
Pat::Path(..) => true,
511-
Pat::ConstBlock(..) => true,
512-
Pat::Lit(expr) => !matches!(
513-
body[*expr],
514-
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
515-
),
516-
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
500+
fn is_non_ref_pat(&mut self, body: &hir_def::body::Body, pat: PatId) -> bool {
501+
match &body[pat] {
502+
Pat::Tuple { .. }
503+
| Pat::TupleStruct { .. }
504+
| Pat::Record { .. }
505+
| Pat::Range { .. }
506+
| Pat::Slice { .. } => true,
507+
Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
508+
Pat::Path(p) => {
509+
let v = self.resolve_value_path_inner(p, pat.into());
510+
v.is_some_and(|x| !matches!(x.0, hir_def::resolver::ValueNs::ConstId(_)))
511+
}
512+
Pat::ConstBlock(..) => false,
513+
Pat::Lit(expr) => !matches!(
514+
body[*expr],
515+
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
516+
),
517+
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => {
518+
false
519+
}
520+
}
517521
}
518522
}
519523

crates/hir-ty/src/infer/path.rs

+36-27
Original file line numberDiff line numberDiff line change
@@ -40,33 +40,7 @@ impl InferenceContext<'_> {
4040
}
4141

4242
fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
43-
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
44-
let last = path.segments().last()?;
45-
46-
// Don't use `self.make_ty()` here as we need `orig_ns`.
47-
let ctx =
48-
crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
49-
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
50-
let ty = self.table.insert_type_vars(ty);
51-
let ty = self.table.normalize_associated_types_in(ty);
52-
53-
let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
54-
let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
55-
let ty = self.table.insert_type_vars(ty);
56-
let ty = self.table.normalize_associated_types_in(ty);
57-
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
58-
} else {
59-
// FIXME: report error, unresolved first path segment
60-
let value_or_partial =
61-
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
62-
63-
match value_or_partial {
64-
ResolveValueResult::ValueNs(it, _) => (it, None),
65-
ResolveValueResult::Partial(def, remaining_index, _) => self
66-
.resolve_assoc_item(def, path, remaining_index, id)
67-
.map(|(it, substs)| (it, Some(substs)))?,
68-
}
69-
};
43+
let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
7044

7145
let value_def = match value {
7246
ValueNs::LocalBinding(pat) => match self.result.type_of_binding.get(pat) {
@@ -144,6 +118,41 @@ impl InferenceContext<'_> {
144118
Some(ValuePathResolution::GenericDef(value_def, generic_def, substs))
145119
}
146120

121+
pub(super) fn resolve_value_path_inner(
122+
&mut self,
123+
path: &Path,
124+
id: ExprOrPatId,
125+
) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
126+
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
127+
let last = path.segments().last()?;
128+
129+
// Don't use `self.make_ty()` here as we need `orig_ns`.
130+
let ctx =
131+
crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
132+
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
133+
let ty = self.table.insert_type_vars(ty);
134+
let ty = self.table.normalize_associated_types_in(ty);
135+
136+
let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
137+
let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
138+
let ty = self.table.insert_type_vars(ty);
139+
let ty = self.table.normalize_associated_types_in(ty);
140+
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
141+
} else {
142+
// FIXME: report error, unresolved first path segment
143+
let value_or_partial =
144+
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
145+
146+
match value_or_partial {
147+
ResolveValueResult::ValueNs(it, _) => (it, None),
148+
ResolveValueResult::Partial(def, remaining_index, _) => self
149+
.resolve_assoc_item(def, path, remaining_index, id)
150+
.map(|(it, substs)| (it, Some(substs)))?,
151+
}
152+
};
153+
Some((value, self_subst))
154+
}
155+
147156
fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) {
148157
let predicates = self.db.generic_predicates(def);
149158
for predicate in predicates.iter() {

crates/hir-ty/src/tests/patterns.rs

+38
Original file line numberDiff line numberDiff line change
@@ -1153,3 +1153,41 @@ fn main() {
11531153
"#,
11541154
);
11551155
}
1156+
1157+
#[test]
1158+
fn type_mismatch_pat_const_reference() {
1159+
check_no_mismatches(
1160+
r#"
1161+
const TEST_STR: &'static str = "abcd";
1162+
1163+
fn main() {
1164+
let s = "abcd";
1165+
match s {
1166+
TEST_STR => (),
1167+
_ => (),
1168+
}
1169+
}
1170+
1171+
"#,
1172+
);
1173+
check(
1174+
r#"
1175+
struct Foo<T>(T);
1176+
1177+
impl<T> Foo<T> {
1178+
const TEST_I32_REF: &'static i32 = &3;
1179+
const TEST_I32: i32 = 3;
1180+
}
1181+
1182+
fn main() {
1183+
match &6 {
1184+
Foo::<i32>::TEST_I32_REF => (),
1185+
Foo::<i32>::TEST_I32 => (),
1186+
//^^^^^^^^^^^^^^^^^^^^ expected &i32, got i32
1187+
_ => (),
1188+
}
1189+
}
1190+
1191+
"#,
1192+
);
1193+
}

xtask/src/metrics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl Metrics {
8686
fn measure_rustc_tests(&mut self, sh: &Shell) -> anyhow::Result<()> {
8787
eprintln!("\nMeasuring rustc tests");
8888

89-
cmd!(sh, "git clone https://github.com/rust-lang/rust").run()?;
89+
cmd!(sh, "git clone --depth=1 https://github.com/rust-lang/rust").run()?;
9090

9191
let output = cmd!(sh, "./target/release/rust-analyzer rustc-tests ./rust").read()?;
9292
for (metric, value, unit) in parse_metrics(&output) {

0 commit comments

Comments
 (0)