Auto merge of #16131 - HKalbasi:rustc-tests-fixup, r=HKalbasi
Fix false positive type mismatch in const reference patterns
This commit is contained in:
commit
21b06c1beb
@ -262,7 +262,7 @@ pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty) {
|
||||
fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty {
|
||||
let mut expected = self.resolve_ty_shallow(expected);
|
||||
|
||||
if is_non_ref_pat(self.body, pat) {
|
||||
if self.is_non_ref_pat(self.body, pat) {
|
||||
let mut pat_adjustments = Vec::new();
|
||||
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
|
||||
pat_adjustments.push(expected.clone());
|
||||
@ -496,24 +496,28 @@ fn infer_lit_pat(&mut self, expr: ExprId, expected: &Ty) -> Ty {
|
||||
|
||||
self.infer_expr(expr, &Expectation::has_type(expected.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
|
||||
match &body[pat] {
|
||||
Pat::Tuple { .. }
|
||||
| Pat::TupleStruct { .. }
|
||||
| Pat::Record { .. }
|
||||
| Pat::Range { .. }
|
||||
| Pat::Slice { .. } => true,
|
||||
Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)),
|
||||
// FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
|
||||
Pat::Path(..) => true,
|
||||
Pat::ConstBlock(..) => true,
|
||||
Pat::Lit(expr) => !matches!(
|
||||
body[*expr],
|
||||
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
|
||||
),
|
||||
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
|
||||
fn is_non_ref_pat(&mut self, body: &hir_def::body::Body, pat: PatId) -> bool {
|
||||
match &body[pat] {
|
||||
Pat::Tuple { .. }
|
||||
| Pat::TupleStruct { .. }
|
||||
| Pat::Record { .. }
|
||||
| Pat::Range { .. }
|
||||
| Pat::Slice { .. } => true,
|
||||
Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
|
||||
Pat::Path(p) => {
|
||||
let v = self.resolve_value_path_inner(p, pat.into());
|
||||
v.is_some_and(|x| !matches!(x.0, hir_def::resolver::ValueNs::ConstId(_)))
|
||||
}
|
||||
Pat::ConstBlock(..) => false,
|
||||
Pat::Lit(expr) => !matches!(
|
||||
body[*expr],
|
||||
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
|
||||
),
|
||||
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,33 +40,7 @@ pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty>
|
||||
}
|
||||
|
||||
fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
|
||||
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
|
||||
let last = path.segments().last()?;
|
||||
|
||||
// Don't use `self.make_ty()` here as we need `orig_ns`.
|
||||
let ctx =
|
||||
crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
|
||||
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
|
||||
let ty = self.table.insert_type_vars(ty);
|
||||
let ty = self.table.normalize_associated_types_in(ty);
|
||||
|
||||
let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
|
||||
let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
|
||||
let ty = self.table.insert_type_vars(ty);
|
||||
let ty = self.table.normalize_associated_types_in(ty);
|
||||
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
|
||||
} else {
|
||||
// FIXME: report error, unresolved first path segment
|
||||
let value_or_partial =
|
||||
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
|
||||
|
||||
match value_or_partial {
|
||||
ResolveValueResult::ValueNs(it, _) => (it, None),
|
||||
ResolveValueResult::Partial(def, remaining_index, _) => self
|
||||
.resolve_assoc_item(def, path, remaining_index, id)
|
||||
.map(|(it, substs)| (it, Some(substs)))?,
|
||||
}
|
||||
};
|
||||
let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
|
||||
|
||||
let value_def = match value {
|
||||
ValueNs::LocalBinding(pat) => match self.result.type_of_binding.get(pat) {
|
||||
@ -144,6 +118,41 @@ fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePa
|
||||
Some(ValuePathResolution::GenericDef(value_def, generic_def, substs))
|
||||
}
|
||||
|
||||
pub(super) fn resolve_value_path_inner(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
id: ExprOrPatId,
|
||||
) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
|
||||
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
|
||||
let last = path.segments().last()?;
|
||||
|
||||
// Don't use `self.make_ty()` here as we need `orig_ns`.
|
||||
let ctx =
|
||||
crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
|
||||
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
|
||||
let ty = self.table.insert_type_vars(ty);
|
||||
let ty = self.table.normalize_associated_types_in(ty);
|
||||
|
||||
let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
|
||||
let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
|
||||
let ty = self.table.insert_type_vars(ty);
|
||||
let ty = self.table.normalize_associated_types_in(ty);
|
||||
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
|
||||
} else {
|
||||
// FIXME: report error, unresolved first path segment
|
||||
let value_or_partial =
|
||||
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
|
||||
|
||||
match value_or_partial {
|
||||
ResolveValueResult::ValueNs(it, _) => (it, None),
|
||||
ResolveValueResult::Partial(def, remaining_index, _) => self
|
||||
.resolve_assoc_item(def, path, remaining_index, id)
|
||||
.map(|(it, substs)| (it, Some(substs)))?,
|
||||
}
|
||||
};
|
||||
Some((value, self_subst))
|
||||
}
|
||||
|
||||
fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) {
|
||||
let predicates = self.db.generic_predicates(def);
|
||||
for predicate in predicates.iter() {
|
||||
|
@ -1153,3 +1153,41 @@ fn main() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_mismatch_pat_const_reference() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
const TEST_STR: &'static str = "abcd";
|
||||
|
||||
fn main() {
|
||||
let s = "abcd";
|
||||
match s {
|
||||
TEST_STR => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
"#,
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
struct Foo<T>(T);
|
||||
|
||||
impl<T> Foo<T> {
|
||||
const TEST_I32_REF: &'static i32 = &3;
|
||||
const TEST_I32: i32 = 3;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match &6 {
|
||||
Foo::<i32>::TEST_I32_REF => (),
|
||||
Foo::<i32>::TEST_I32 => (),
|
||||
//^^^^^^^^^^^^^^^^^^^^ expected &i32, got i32
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ fn measure_build(&mut self, sh: &Shell) -> anyhow::Result<()> {
|
||||
fn measure_rustc_tests(&mut self, sh: &Shell) -> anyhow::Result<()> {
|
||||
eprintln!("\nMeasuring rustc tests");
|
||||
|
||||
cmd!(sh, "git clone https://github.com/rust-lang/rust").run()?;
|
||||
cmd!(sh, "git clone --depth=1 https://github.com/rust-lang/rust").run()?;
|
||||
|
||||
let output = cmd!(sh, "./target/release/rust-analyzer rustc-tests ./rust").read()?;
|
||||
for (metric, value, unit) in parse_metrics(&output) {
|
||||
|
Loading…
Reference in New Issue
Block a user