Merge pull request #19167 from ChayimFriedman2/fix-ref-pat
fix: Fix detection of ref patterns for path patterns
This commit is contained in:
commit
2a0d16f3c4
4 changed files with 64 additions and 17 deletions
|
@ -7,6 +7,7 @@ use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{hir::ExprOrPatId, path::Path, resolver::Resolver, type_ref::TypesMap, TypeOwnerId};
|
use hir_def::{hir::ExprOrPatId, path::Path, resolver::Resolver, type_ref::TypesMap, TypeOwnerId};
|
||||||
|
use la_arena::{Idx, RawIdx};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
|
@ -81,6 +82,26 @@ impl<'a> InferenceTyLoweringContext<'a> {
|
||||||
};
|
};
|
||||||
PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
|
PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn at_path_forget_diagnostics<'b>(
|
||||||
|
&'b mut self,
|
||||||
|
path: &'b Path,
|
||||||
|
) -> PathLoweringContext<'b, 'a> {
|
||||||
|
let on_diagnostic = PathDiagnosticCallback {
|
||||||
|
data: Either::Right(PathDiagnosticCallbackData {
|
||||||
|
diagnostics: self.diagnostics,
|
||||||
|
node: ExprOrPatId::ExprId(Idx::from_raw(RawIdx::from_u32(0))),
|
||||||
|
}),
|
||||||
|
callback: |_data, _, _diag| {},
|
||||||
|
};
|
||||||
|
PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn forget_diagnostics(&mut self) {
|
||||||
|
self.ctx.diagnostics.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deref for InferenceTyLoweringContext<'a> {
|
impl<'a> Deref for InferenceTyLoweringContext<'a> {
|
||||||
|
|
|
@ -565,16 +565,9 @@ impl InferenceContext<'_> {
|
||||||
| Pat::Slice { .. } => true,
|
| Pat::Slice { .. } => true,
|
||||||
Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
|
Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
|
||||||
Pat::Path(path) => {
|
Pat::Path(path) => {
|
||||||
// A const is a reference pattern, but other value ns things aren't (see #16131). We don't need more than
|
// A const is a reference pattern, but other value ns things aren't (see #16131).
|
||||||
// the hir-def resolver for this, because if there are segments left, this can only be an (associated) const.
|
let resolved = self.resolve_value_path_inner(path, pat.into(), true);
|
||||||
//
|
resolved.is_some_and(|it| !matches!(it.0, hir_def::resolver::ValueNs::ConstId(_)))
|
||||||
// Do not use `TyLoweringContext`'s resolution, we want to ignore errors here (they'll be reported elsewhere).
|
|
||||||
let resolution = self.resolver.resolve_path_in_value_ns_fully(
|
|
||||||
self.db.upcast(),
|
|
||||||
path,
|
|
||||||
body.pat_path_hygiene(pat),
|
|
||||||
);
|
|
||||||
resolution.is_some_and(|it| !matches!(it, hir_def::resolver::ValueNs::ConstId(_)))
|
|
||||||
}
|
}
|
||||||
Pat::ConstBlock(..) => false,
|
Pat::ConstBlock(..) => false,
|
||||||
Pat::Lit(expr) => !matches!(
|
Pat::Lit(expr) => !matches!(
|
||||||
|
|
|
@ -40,7 +40,7 @@ impl InferenceContext<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
|
fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
|
||||||
let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
|
let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?;
|
||||||
|
|
||||||
let value_def: ValueTyDefId = match value {
|
let value_def: ValueTyDefId = match value {
|
||||||
ValueNs::FunctionId(it) => it.into(),
|
ValueNs::FunctionId(it) => it.into(),
|
||||||
|
@ -152,6 +152,7 @@ impl InferenceContext<'_> {
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
id: ExprOrPatId,
|
id: ExprOrPatId,
|
||||||
|
no_diagnostics: bool,
|
||||||
) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
|
) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
|
||||||
// Don't use `self.make_ty()` here as we need `orig_ns`.
|
// Don't use `self.make_ty()` here as we need `orig_ns`.
|
||||||
let mut ctx = TyLoweringContext::new(
|
let mut ctx = TyLoweringContext::new(
|
||||||
|
@ -162,7 +163,11 @@ impl InferenceContext<'_> {
|
||||||
&self.diagnostics,
|
&self.diagnostics,
|
||||||
InferenceTyDiagnosticSource::Body,
|
InferenceTyDiagnosticSource::Body,
|
||||||
);
|
);
|
||||||
let mut path_ctx = ctx.at_path(path, id);
|
let mut path_ctx = if no_diagnostics {
|
||||||
|
ctx.at_path_forget_diagnostics(path)
|
||||||
|
} else {
|
||||||
|
ctx.at_path(path, id)
|
||||||
|
};
|
||||||
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
|
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
|
||||||
let last = path.segments().last()?;
|
let last = path.segments().last()?;
|
||||||
|
|
||||||
|
@ -172,7 +177,7 @@ impl InferenceContext<'_> {
|
||||||
|
|
||||||
path_ctx.ignore_last_segment();
|
path_ctx.ignore_last_segment();
|
||||||
let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns);
|
let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns);
|
||||||
drop(ctx);
|
drop_ctx(ctx, no_diagnostics);
|
||||||
let ty = self.table.insert_type_vars(ty);
|
let ty = self.table.insert_type_vars(ty);
|
||||||
let ty = self.table.normalize_associated_types_in(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)))?
|
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
|
||||||
|
@ -183,7 +188,7 @@ impl InferenceContext<'_> {
|
||||||
|
|
||||||
match value_or_partial {
|
match value_or_partial {
|
||||||
ResolveValueResult::ValueNs(it, _) => {
|
ResolveValueResult::ValueNs(it, _) => {
|
||||||
drop(ctx);
|
drop_ctx(ctx, no_diagnostics);
|
||||||
(it, None)
|
(it, None)
|
||||||
}
|
}
|
||||||
ResolveValueResult::Partial(def, remaining_index, _) => {
|
ResolveValueResult::Partial(def, remaining_index, _) => {
|
||||||
|
@ -202,7 +207,7 @@ impl InferenceContext<'_> {
|
||||||
let self_ty = self.table.new_type_var();
|
let self_ty = self.table.new_type_var();
|
||||||
let trait_ref =
|
let trait_ref =
|
||||||
path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty);
|
path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty);
|
||||||
drop(ctx);
|
drop_ctx(ctx, no_diagnostics);
|
||||||
self.resolve_trait_assoc_item(trait_ref, last_segment, id)
|
self.resolve_trait_assoc_item(trait_ref, last_segment, id)
|
||||||
}
|
}
|
||||||
(def, _) => {
|
(def, _) => {
|
||||||
|
@ -212,7 +217,7 @@ impl InferenceContext<'_> {
|
||||||
// as Iterator>::Item::default`)
|
// as Iterator>::Item::default`)
|
||||||
path_ctx.ignore_last_segment();
|
path_ctx.ignore_last_segment();
|
||||||
let (ty, _) = path_ctx.lower_partly_resolved_path(def, true);
|
let (ty, _) = path_ctx.lower_partly_resolved_path(def, true);
|
||||||
drop(ctx);
|
drop_ctx(ctx, no_diagnostics);
|
||||||
if ty.is_unknown() {
|
if ty.is_unknown() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -227,7 +232,14 @@ impl InferenceContext<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some((value, self_subst))
|
return Some((value, self_subst));
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn drop_ctx(mut ctx: TyLoweringContext<'_>, no_diagnostics: bool) {
|
||||||
|
if no_diagnostics {
|
||||||
|
ctx.forget_diagnostics();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) {
|
fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) {
|
||||||
|
|
|
@ -1231,6 +1231,27 @@ fn f() {
|
||||||
fn f() {
|
fn f() {
|
||||||
let (_, _, _, ..) = (true, 42);
|
let (_, _, _, ..) = (true, 42);
|
||||||
// ^^^^^^^^^^^^^ error: expected (bool, i32), found (bool, i32, {unknown})
|
// ^^^^^^^^^^^^^ error: expected (bool, i32), found (bool, i32, {unknown})
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn complex_enum_variant_non_ref_pat() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
enum Enum { Variant }
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
impl Trait for () {
|
||||||
|
type Assoc = Enum;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(v: &Enum) {
|
||||||
|
let <Enum>::Variant = v;
|
||||||
|
let <() as Trait>::Assoc::Variant = v;
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue