mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge pull request #18743 from ChayimFriedman2/e0107
feat: Unify handling of path diagnostics in hir-ty
This commit is contained in:
commit
493ac4d4df
15 changed files with 881 additions and 275 deletions
|
@ -85,6 +85,8 @@ use crate::{
|
||||||
FxIndexMap, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
|
FxIndexMap, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use self::path_resolution::ResolvePathResultPrefixInfo;
|
||||||
|
|
||||||
const PREDEFINED_TOOLS: &[SmolStr] = &[
|
const PREDEFINED_TOOLS: &[SmolStr] = &[
|
||||||
SmolStr::new_static("clippy"),
|
SmolStr::new_static("clippy"),
|
||||||
SmolStr::new_static("rustfmt"),
|
SmolStr::new_static("rustfmt"),
|
||||||
|
@ -615,13 +617,15 @@ impl DefMap {
|
||||||
(res.resolved_def, res.segment_index)
|
(res.resolved_def, res.segment_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The first `Option<usize>` points at the `Enum` segment in case of `Enum::Variant`, the second
|
||||||
|
/// points at the unresolved segments.
|
||||||
pub(crate) fn resolve_path_locally(
|
pub(crate) fn resolve_path_locally(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
original_module: LocalModuleId,
|
original_module: LocalModuleId,
|
||||||
path: &ModPath,
|
path: &ModPath,
|
||||||
shadow: BuiltinShadowMode,
|
shadow: BuiltinShadowMode,
|
||||||
) -> (PerNs, Option<usize>) {
|
) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) {
|
||||||
let res = self.resolve_path_fp_with_macro_single(
|
let res = self.resolve_path_fp_with_macro_single(
|
||||||
db,
|
db,
|
||||||
ResolveMode::Other,
|
ResolveMode::Other,
|
||||||
|
@ -630,7 +634,7 @@ impl DefMap {
|
||||||
shadow,
|
shadow,
|
||||||
None, // Currently this function isn't used for macro resolution.
|
None, // Currently this function isn't used for macro resolution.
|
||||||
);
|
);
|
||||||
(res.resolved_def, res.segment_index)
|
(res.resolved_def, res.segment_index, res.prefix_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
|
/// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
|
||||||
|
|
|
@ -38,7 +38,7 @@ use crate::{
|
||||||
attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id},
|
attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id},
|
||||||
diagnostics::DefDiagnostic,
|
diagnostics::DefDiagnostic,
|
||||||
mod_resolution::ModDir,
|
mod_resolution::ModDir,
|
||||||
path_resolution::ReachedFixedPoint,
|
path_resolution::{ReachedFixedPoint, ResolvePathResultPrefixInfo},
|
||||||
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
|
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
|
||||||
sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin,
|
sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin,
|
||||||
ResolveMode,
|
ResolveMode,
|
||||||
|
@ -797,7 +797,7 @@ impl DefCollector<'_> {
|
||||||
return PartialResolvedImport::Unresolved;
|
return PartialResolvedImport::Unresolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.from_differing_crate {
|
if let ResolvePathResultPrefixInfo::DifferingCrate = res.prefix_info {
|
||||||
return PartialResolvedImport::Resolved(
|
return PartialResolvedImport::Resolved(
|
||||||
def.filter_visibility(|v| matches!(v, Visibility::Public)),
|
def.filter_visibility(|v| matches!(v, Visibility::Public)),
|
||||||
);
|
);
|
||||||
|
|
|
@ -43,21 +43,34 @@ pub(super) struct ResolvePathResult {
|
||||||
pub(super) resolved_def: PerNs,
|
pub(super) resolved_def: PerNs,
|
||||||
pub(super) segment_index: Option<usize>,
|
pub(super) segment_index: Option<usize>,
|
||||||
pub(super) reached_fixedpoint: ReachedFixedPoint,
|
pub(super) reached_fixedpoint: ReachedFixedPoint,
|
||||||
pub(super) from_differing_crate: bool,
|
pub(super) prefix_info: ResolvePathResultPrefixInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ResolvePathResultPrefixInfo {
|
||||||
|
None,
|
||||||
|
DifferingCrate,
|
||||||
|
/// Path of the form `Enum::Variant` (and not `Variant` alone).
|
||||||
|
Enum,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResolvePathResult {
|
impl ResolvePathResult {
|
||||||
fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
|
fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
|
||||||
ResolvePathResult::new(PerNs::none(), reached_fixedpoint, None, false)
|
ResolvePathResult::new(
|
||||||
|
PerNs::none(),
|
||||||
|
reached_fixedpoint,
|
||||||
|
None,
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
resolved_def: PerNs,
|
resolved_def: PerNs,
|
||||||
reached_fixedpoint: ReachedFixedPoint,
|
reached_fixedpoint: ReachedFixedPoint,
|
||||||
segment_index: Option<usize>,
|
segment_index: Option<usize>,
|
||||||
from_differing_crate: bool,
|
prefix_info: ResolvePathResultPrefixInfo,
|
||||||
) -> ResolvePathResult {
|
) -> ResolvePathResult {
|
||||||
ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, from_differing_crate }
|
ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, prefix_info }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +170,17 @@ impl DefMap {
|
||||||
if result.reached_fixedpoint == ReachedFixedPoint::No {
|
if result.reached_fixedpoint == ReachedFixedPoint::No {
|
||||||
result.reached_fixedpoint = new.reached_fixedpoint;
|
result.reached_fixedpoint = new.reached_fixedpoint;
|
||||||
}
|
}
|
||||||
result.from_differing_crate |= new.from_differing_crate;
|
result.prefix_info = match (result.prefix_info, new.prefix_info) {
|
||||||
|
(ResolvePathResultPrefixInfo::None, it) => it,
|
||||||
|
(ResolvePathResultPrefixInfo::DifferingCrate, _) => {
|
||||||
|
ResolvePathResultPrefixInfo::DifferingCrate
|
||||||
|
}
|
||||||
|
(
|
||||||
|
ResolvePathResultPrefixInfo::Enum,
|
||||||
|
ResolvePathResultPrefixInfo::DifferingCrate,
|
||||||
|
) => ResolvePathResultPrefixInfo::DifferingCrate,
|
||||||
|
(ResolvePathResultPrefixInfo::Enum, _) => ResolvePathResultPrefixInfo::Enum,
|
||||||
|
};
|
||||||
result.segment_index = match (result.segment_index, new.segment_index) {
|
result.segment_index = match (result.segment_index, new.segment_index) {
|
||||||
(Some(idx), None) => Some(idx),
|
(Some(idx), None) => Some(idx),
|
||||||
(Some(old), Some(new)) => Some(old.max(new)),
|
(Some(old), Some(new)) => Some(old.max(new)),
|
||||||
|
@ -403,14 +426,14 @@ impl DefMap {
|
||||||
|
|
||||||
fn resolve_remaining_segments<'a>(
|
fn resolve_remaining_segments<'a>(
|
||||||
&self,
|
&self,
|
||||||
segments: impl Iterator<Item = (usize, &'a Name)>,
|
mut segments: impl Iterator<Item = (usize, &'a Name)>,
|
||||||
mut curr_per_ns: PerNs,
|
mut curr_per_ns: PerNs,
|
||||||
path: &ModPath,
|
path: &ModPath,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
shadow: BuiltinShadowMode,
|
shadow: BuiltinShadowMode,
|
||||||
original_module: LocalModuleId,
|
original_module: LocalModuleId,
|
||||||
) -> ResolvePathResult {
|
) -> ResolvePathResult {
|
||||||
for (i, segment) in segments {
|
while let Some((i, segment)) = segments.next() {
|
||||||
let curr = match curr_per_ns.take_types_full() {
|
let curr = match curr_per_ns.take_types_full() {
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
None => {
|
None => {
|
||||||
|
@ -443,7 +466,7 @@ impl DefMap {
|
||||||
def,
|
def,
|
||||||
ReachedFixedPoint::Yes,
|
ReachedFixedPoint::Yes,
|
||||||
s.map(|s| s + i),
|
s.map(|s| s + i),
|
||||||
true,
|
ResolvePathResultPrefixInfo::DifferingCrate,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,17 +511,28 @@ impl DefMap {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
match res {
|
// FIXME: Need to filter visibility here and below? Not sure.
|
||||||
Some(res) => res,
|
return match res {
|
||||||
None => {
|
Some(res) => {
|
||||||
return ResolvePathResult::new(
|
if segments.next().is_some() {
|
||||||
PerNs::types(e.into(), curr.vis, curr.import),
|
// Enum variants are in value namespace, segments left => no resolution.
|
||||||
|
ResolvePathResult::empty(ReachedFixedPoint::No)
|
||||||
|
} else {
|
||||||
|
ResolvePathResult::new(
|
||||||
|
res,
|
||||||
ReachedFixedPoint::Yes,
|
ReachedFixedPoint::Yes,
|
||||||
Some(i),
|
None,
|
||||||
false,
|
ResolvePathResultPrefixInfo::Enum,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None => ResolvePathResult::new(
|
||||||
|
PerNs::types(e.into(), curr.vis, curr.import),
|
||||||
|
ReachedFixedPoint::Yes,
|
||||||
|
Some(i),
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
s => {
|
s => {
|
||||||
// could be an inherent method call in UFCS form
|
// could be an inherent method call in UFCS form
|
||||||
|
@ -513,7 +547,7 @@ impl DefMap {
|
||||||
PerNs::types(s, curr.vis, curr.import),
|
PerNs::types(s, curr.vis, curr.import),
|
||||||
ReachedFixedPoint::Yes,
|
ReachedFixedPoint::Yes,
|
||||||
Some(i),
|
Some(i),
|
||||||
false,
|
ResolvePathResultPrefixInfo::None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -522,7 +556,12 @@ impl DefMap {
|
||||||
.filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module));
|
.filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvePathResult::new(curr_per_ns, ReachedFixedPoint::Yes, None, false)
|
ResolvePathResult::new(
|
||||||
|
curr_per_ns,
|
||||||
|
ReachedFixedPoint::Yes,
|
||||||
|
None,
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_name_in_module(
|
fn resolve_name_in_module(
|
||||||
|
|
|
@ -240,6 +240,7 @@ pub struct PathSegment<'a> {
|
||||||
pub args_and_bindings: Option<&'a GenericArgs>,
|
pub args_and_bindings: Option<&'a GenericArgs>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct PathSegments<'a> {
|
pub struct PathSegments<'a> {
|
||||||
segments: &'a [Name],
|
segments: &'a [Name],
|
||||||
generic_args: Option<&'a [Option<GenericArgs>]>,
|
generic_args: Option<&'a [Option<GenericArgs>]>,
|
||||||
|
@ -259,6 +260,7 @@ impl<'a> PathSegments<'a> {
|
||||||
pub fn last(&self) -> Option<PathSegment<'a>> {
|
pub fn last(&self) -> Option<PathSegment<'a>> {
|
||||||
self.get(self.len().checked_sub(1)?)
|
self.get(self.len().checked_sub(1)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
|
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
|
||||||
let res = PathSegment {
|
let res = PathSegment {
|
||||||
name: self.segments.get(idx)?,
|
name: self.segments.get(idx)?,
|
||||||
|
@ -266,24 +268,37 @@ impl<'a> PathSegments<'a> {
|
||||||
};
|
};
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip(&self, len: usize) -> PathSegments<'a> {
|
pub fn skip(&self, len: usize) -> PathSegments<'a> {
|
||||||
PathSegments {
|
PathSegments {
|
||||||
segments: self.segments.get(len..).unwrap_or(&[]),
|
segments: self.segments.get(len..).unwrap_or(&[]),
|
||||||
generic_args: self.generic_args.and_then(|it| it.get(len..)),
|
generic_args: self.generic_args.and_then(|it| it.get(len..)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take(&self, len: usize) -> PathSegments<'a> {
|
pub fn take(&self, len: usize) -> PathSegments<'a> {
|
||||||
PathSegments {
|
PathSegments {
|
||||||
segments: self.segments.get(..len).unwrap_or(self.segments),
|
segments: self.segments.get(..len).unwrap_or(self.segments),
|
||||||
generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)),
|
generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn strip_last(&self) -> PathSegments<'a> {
|
pub fn strip_last(&self) -> PathSegments<'a> {
|
||||||
PathSegments {
|
PathSegments {
|
||||||
segments: self.segments.split_last().map_or(&[], |it| it.1),
|
segments: self.segments.split_last().map_or(&[], |it| it.1),
|
||||||
generic_args: self.generic_args.map(|it| it.split_last().map_or(&[][..], |it| it.1)),
|
generic_args: self.generic_args.map(|it| it.split_last().map_or(&[][..], |it| it.1)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn strip_last_two(&self) -> PathSegments<'a> {
|
||||||
|
PathSegments {
|
||||||
|
segments: self.segments.get(..self.segments.len().saturating_sub(2)).unwrap_or(&[]),
|
||||||
|
generic_args: self
|
||||||
|
.generic_args
|
||||||
|
.map(|it| it.get(..it.len().saturating_sub(2)).unwrap_or(&[])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
|
pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
|
||||||
self.segments
|
self.segments
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::{
|
||||||
hir::{BindingId, ExprId, LabelId},
|
hir::{BindingId, ExprId, LabelId},
|
||||||
item_scope::{BuiltinShadowMode, ImportId, ImportOrExternCrate, BUILTIN_SCOPE},
|
item_scope::{BuiltinShadowMode, ImportId, ImportOrExternCrate, BUILTIN_SCOPE},
|
||||||
lang_item::LangItemTarget,
|
lang_item::LangItemTarget,
|
||||||
nameres::{DefMap, MacroSubNs},
|
nameres::{DefMap, MacroSubNs, ResolvePathResultPrefixInfo},
|
||||||
path::{ModPath, Path, PathKind},
|
path::{ModPath, Path, PathKind},
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
type_ref::{LifetimeRef, TypesMap},
|
type_ref::{LifetimeRef, TypesMap},
|
||||||
|
@ -263,13 +263,23 @@ impl Resolver {
|
||||||
&self,
|
&self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
mut hygiene_id: HygieneId,
|
hygiene_id: HygieneId,
|
||||||
) -> Option<ResolveValueResult> {
|
) -> Option<ResolveValueResult> {
|
||||||
|
self.resolve_path_in_value_ns_with_prefix_info(db, path, hygiene_id).map(|(it, _)| it)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_path_in_value_ns_with_prefix_info(
|
||||||
|
&self,
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
path: &Path,
|
||||||
|
mut hygiene_id: HygieneId,
|
||||||
|
) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> {
|
||||||
let path = match path {
|
let path = match path {
|
||||||
Path::BarePath(mod_path) => mod_path,
|
Path::BarePath(mod_path) => mod_path,
|
||||||
Path::Normal(it) => it.mod_path(),
|
Path::Normal(it) => it.mod_path(),
|
||||||
Path::LangItem(l, None) => {
|
Path::LangItem(l, None) => {
|
||||||
return Some(ResolveValueResult::ValueNs(
|
return Some((
|
||||||
|
ResolveValueResult::ValueNs(
|
||||||
match *l {
|
match *l {
|
||||||
LangItemTarget::Function(it) => ValueNs::FunctionId(it),
|
LangItemTarget::Function(it) => ValueNs::FunctionId(it),
|
||||||
LangItemTarget::Static(it) => ValueNs::StaticId(it),
|
LangItemTarget::Static(it) => ValueNs::StaticId(it),
|
||||||
|
@ -282,6 +292,8 @@ impl Resolver {
|
||||||
| LangItemTarget::EnumId(_) => return None,
|
| LangItemTarget::EnumId(_) => return None,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
|
),
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Path::LangItem(l, Some(_)) => {
|
Path::LangItem(l, Some(_)) => {
|
||||||
|
@ -296,7 +308,10 @@ impl Resolver {
|
||||||
| LangItemTarget::ImplDef(_)
|
| LangItemTarget::ImplDef(_)
|
||||||
| LangItemTarget::Static(_) => return None,
|
| LangItemTarget::Static(_) => return None,
|
||||||
};
|
};
|
||||||
return Some(ResolveValueResult::Partial(type_ns, 1, None));
|
return Some((
|
||||||
|
ResolveValueResult::Partial(type_ns, 1, None),
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let n_segments = path.segments().len();
|
let n_segments = path.segments().len();
|
||||||
|
@ -326,9 +341,12 @@ impl Resolver {
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(e) = entry {
|
if let Some(e) = entry {
|
||||||
return Some(ResolveValueResult::ValueNs(
|
return Some((
|
||||||
|
ResolveValueResult::ValueNs(
|
||||||
ValueNs::LocalBinding(e.binding()),
|
ValueNs::LocalBinding(e.binding()),
|
||||||
None,
|
None,
|
||||||
|
),
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,14 +368,17 @@ impl Resolver {
|
||||||
Scope::GenericParams { params, def } => {
|
Scope::GenericParams { params, def } => {
|
||||||
if let Some(id) = params.find_const_by_name(first_name, *def) {
|
if let Some(id) = params.find_const_by_name(first_name, *def) {
|
||||||
let val = ValueNs::GenericParam(id);
|
let val = ValueNs::GenericParam(id);
|
||||||
return Some(ResolveValueResult::ValueNs(val, None));
|
return Some((
|
||||||
|
ResolveValueResult::ValueNs(val, None),
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Scope::ImplDefScope(impl_) => {
|
&Scope::ImplDefScope(impl_) => {
|
||||||
if *first_name == sym::Self_.clone() {
|
if *first_name == sym::Self_.clone() {
|
||||||
return Some(ResolveValueResult::ValueNs(
|
return Some((
|
||||||
ValueNs::ImplSelf(impl_),
|
ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None),
|
||||||
None,
|
ResolvePathResultPrefixInfo::None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,22 +398,27 @@ impl Resolver {
|
||||||
Scope::GenericParams { params, def } => {
|
Scope::GenericParams { params, def } => {
|
||||||
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
||||||
let ty = TypeNs::GenericParam(id);
|
let ty = TypeNs::GenericParam(id);
|
||||||
return Some(ResolveValueResult::Partial(ty, 1, None));
|
return Some((
|
||||||
|
ResolveValueResult::Partial(ty, 1, None),
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Scope::ImplDefScope(impl_) => {
|
&Scope::ImplDefScope(impl_) => {
|
||||||
if *first_name == sym::Self_.clone() {
|
if *first_name == sym::Self_.clone() {
|
||||||
return Some(ResolveValueResult::Partial(
|
return Some((
|
||||||
TypeNs::SelfType(impl_),
|
ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1, None),
|
||||||
1,
|
ResolvePathResultPrefixInfo::None,
|
||||||
None,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::AdtScope(adt) => {
|
Scope::AdtScope(adt) => {
|
||||||
if *first_name == sym::Self_.clone() {
|
if *first_name == sym::Self_.clone() {
|
||||||
let ty = TypeNs::AdtSelfType(*adt);
|
let ty = TypeNs::AdtSelfType(*adt);
|
||||||
return Some(ResolveValueResult::Partial(ty, 1, None));
|
return Some((
|
||||||
|
ResolveValueResult::Partial(ty, 1, None),
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::BlockScope(m) => {
|
Scope::BlockScope(m) => {
|
||||||
|
@ -413,7 +439,10 @@ impl Resolver {
|
||||||
// `use core::u16;`.
|
// `use core::u16;`.
|
||||||
if path.kind == PathKind::Plain && n_segments > 1 {
|
if path.kind == PathKind::Plain && n_segments > 1 {
|
||||||
if let Some(builtin) = BuiltinType::by_name(first_name) {
|
if let Some(builtin) = BuiltinType::by_name(first_name) {
|
||||||
return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None));
|
return Some((
|
||||||
|
ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None),
|
||||||
|
ResolvePathResultPrefixInfo::None,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,15 +953,15 @@ impl ModuleItemMap {
|
||||||
&self,
|
&self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
path: &ModPath,
|
path: &ModPath,
|
||||||
) -> Option<ResolveValueResult> {
|
) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> {
|
||||||
let (module_def, idx) =
|
let (module_def, unresolved_idx, prefix_info) =
|
||||||
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
|
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
|
||||||
match idx {
|
match unresolved_idx {
|
||||||
None => {
|
None => {
|
||||||
let (value, import) = to_value_ns(module_def)?;
|
let (value, import) = to_value_ns(module_def)?;
|
||||||
Some(ResolveValueResult::ValueNs(value, import))
|
Some((ResolveValueResult::ValueNs(value, import), prefix_info))
|
||||||
}
|
}
|
||||||
Some(idx) => {
|
Some(unresolved_idx) => {
|
||||||
let def = module_def.take_types_full()?;
|
let def = module_def.take_types_full()?;
|
||||||
let ty = match def.def {
|
let ty = match def.def {
|
||||||
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
||||||
|
@ -948,7 +977,7 @@ impl ModuleItemMap {
|
||||||
| ModuleDefId::MacroId(_)
|
| ModuleDefId::MacroId(_)
|
||||||
| ModuleDefId::StaticId(_) => return None,
|
| ModuleDefId::StaticId(_) => return None,
|
||||||
};
|
};
|
||||||
Some(ResolveValueResult::Partial(ty, idx, def.import))
|
Some((ResolveValueResult::Partial(ty, unresolved_idx, def.import), prefix_info))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -958,7 +987,7 @@ impl ModuleItemMap {
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
path: &ModPath,
|
path: &ModPath,
|
||||||
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
|
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
|
||||||
let (module_def, idx) =
|
let (module_def, idx, _) =
|
||||||
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
|
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
|
||||||
let (res, import) = to_type_ns(module_def)?;
|
let (res, import) = to_type_ns(module_def)?;
|
||||||
Some((res, idx, import))
|
Some((res, idx, import))
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
pub(crate) mod cast;
|
pub(crate) mod cast;
|
||||||
pub(crate) mod closure;
|
pub(crate) mod closure;
|
||||||
mod coerce;
|
mod coerce;
|
||||||
|
mod diagnostics;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod mutability;
|
mod mutability;
|
||||||
mod pat;
|
mod pat;
|
||||||
|
@ -57,15 +58,20 @@ use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
fold_tys,
|
fold_tys,
|
||||||
generics::Generics,
|
generics::Generics,
|
||||||
infer::{coerce::CoerceMany, expr::ExprIsRead, unify::InferenceTable},
|
infer::{
|
||||||
lower::{ImplTraitLoweringMode, TyLoweringDiagnostic},
|
coerce::CoerceMany,
|
||||||
|
diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext},
|
||||||
|
expr::ExprIsRead,
|
||||||
|
unify::InferenceTable,
|
||||||
|
},
|
||||||
|
lower::{diagnostics::TyLoweringDiagnostic, ImplTraitLoweringMode},
|
||||||
mir::MirSpan,
|
mir::MirSpan,
|
||||||
to_assoc_type_id,
|
to_assoc_type_id,
|
||||||
traits::FnTrait,
|
traits::FnTrait,
|
||||||
utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
|
utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
|
||||||
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
|
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
|
||||||
ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, ProjectionTy,
|
ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode,
|
||||||
Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
|
PathLoweringDiagnostic, ProjectionTy, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This lint has a false positive here. See the link below for details.
|
// This lint has a false positive here. See the link below for details.
|
||||||
|
@ -276,6 +282,10 @@ pub enum InferenceDiagnostic {
|
||||||
source: InferenceTyDiagnosticSource,
|
source: InferenceTyDiagnosticSource,
|
||||||
diag: TyLoweringDiagnostic,
|
diag: TyLoweringDiagnostic,
|
||||||
},
|
},
|
||||||
|
PathDiagnostic {
|
||||||
|
node: ExprOrPatId,
|
||||||
|
diag: PathLoweringDiagnostic,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mismatch between an expected and an inferred type.
|
/// A mismatch between an expected and an inferred type.
|
||||||
|
@ -442,6 +452,7 @@ pub struct InferenceResult {
|
||||||
/// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of
|
/// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of
|
||||||
/// that which allows us to resolve a [`TupleFieldId`]s type.
|
/// that which allows us to resolve a [`TupleFieldId`]s type.
|
||||||
pub tuple_field_access_types: FxHashMap<TupleId, Substitution>,
|
pub tuple_field_access_types: FxHashMap<TupleId, Substitution>,
|
||||||
|
/// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead.
|
||||||
pub diagnostics: Vec<InferenceDiagnostic>,
|
pub diagnostics: Vec<InferenceDiagnostic>,
|
||||||
pub type_of_expr: ArenaMap<ExprId, Ty>,
|
pub type_of_expr: ArenaMap<ExprId, Ty>,
|
||||||
/// For each pattern record the type it resolves to.
|
/// For each pattern record the type it resolves to.
|
||||||
|
@ -579,6 +590,8 @@ pub(crate) struct InferenceContext<'a> {
|
||||||
pub(crate) db: &'a dyn HirDatabase,
|
pub(crate) db: &'a dyn HirDatabase,
|
||||||
pub(crate) owner: DefWithBodyId,
|
pub(crate) owner: DefWithBodyId,
|
||||||
pub(crate) body: &'a Body,
|
pub(crate) body: &'a Body,
|
||||||
|
/// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext
|
||||||
|
/// and resolve the path via its methods. This will ensure proper error reporting.
|
||||||
pub(crate) resolver: Resolver,
|
pub(crate) resolver: Resolver,
|
||||||
generics: OnceCell<Option<Generics>>,
|
generics: OnceCell<Option<Generics>>,
|
||||||
table: unify::InferenceTable<'a>,
|
table: unify::InferenceTable<'a>,
|
||||||
|
@ -620,6 +633,8 @@ pub(crate) struct InferenceContext<'a> {
|
||||||
/// comment on `InferenceContext::sort_closures`
|
/// comment on `InferenceContext::sort_closures`
|
||||||
closure_dependencies: FxHashMap<ClosureId, Vec<ClosureId>>,
|
closure_dependencies: FxHashMap<ClosureId, Vec<ClosureId>>,
|
||||||
deferred_closures: FxHashMap<ClosureId, Vec<(Ty, Ty, Vec<Ty>, ExprId)>>,
|
deferred_closures: FxHashMap<ClosureId, Vec<(Ty, Ty, Vec<Ty>, ExprId)>>,
|
||||||
|
|
||||||
|
diagnostics: Diagnostics,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -701,6 +716,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
deferred_closures: FxHashMap::default(),
|
deferred_closures: FxHashMap::default(),
|
||||||
closure_dependencies: FxHashMap::default(),
|
closure_dependencies: FxHashMap::default(),
|
||||||
inside_assignment: false,
|
inside_assignment: false,
|
||||||
|
diagnostics: Diagnostics::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,8 +740,10 @@ impl<'a> InferenceContext<'a> {
|
||||||
mut result,
|
mut result,
|
||||||
mut deferred_cast_checks,
|
mut deferred_cast_checks,
|
||||||
tuple_field_accesses_rev,
|
tuple_field_accesses_rev,
|
||||||
|
diagnostics,
|
||||||
..
|
..
|
||||||
} = self;
|
} = self;
|
||||||
|
let mut diagnostics = diagnostics.finish();
|
||||||
// Destructure every single field so whenever new fields are added to `InferenceResult` we
|
// Destructure every single field so whenever new fields are added to `InferenceResult` we
|
||||||
// don't forget to handle them here.
|
// don't forget to handle them here.
|
||||||
let InferenceResult {
|
let InferenceResult {
|
||||||
|
@ -733,7 +751,6 @@ impl<'a> InferenceContext<'a> {
|
||||||
field_resolutions: _,
|
field_resolutions: _,
|
||||||
variant_resolutions: _,
|
variant_resolutions: _,
|
||||||
assoc_resolutions,
|
assoc_resolutions,
|
||||||
diagnostics,
|
|
||||||
type_of_expr,
|
type_of_expr,
|
||||||
type_of_pat,
|
type_of_pat,
|
||||||
type_of_binding,
|
type_of_binding,
|
||||||
|
@ -752,6 +769,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
mutated_bindings_in_closure: _,
|
mutated_bindings_in_closure: _,
|
||||||
tuple_field_access_types: _,
|
tuple_field_access_types: _,
|
||||||
coercion_casts,
|
coercion_casts,
|
||||||
|
diagnostics: _,
|
||||||
} = &mut result;
|
} = &mut result;
|
||||||
table.fallback_if_possible();
|
table.fallback_if_possible();
|
||||||
|
|
||||||
|
@ -866,6 +884,9 @@ impl<'a> InferenceContext<'a> {
|
||||||
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
|
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
result.diagnostics = diagnostics;
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1238,41 +1259,28 @@ impl<'a> InferenceContext<'a> {
|
||||||
self.result.type_of_binding.insert(id, ty);
|
self.result.type_of_binding.insert(id, ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
|
fn push_diagnostic(&self, diagnostic: InferenceDiagnostic) {
|
||||||
self.result.diagnostics.push(diagnostic);
|
self.diagnostics.push(diagnostic);
|
||||||
}
|
|
||||||
|
|
||||||
fn push_ty_diagnostics(
|
|
||||||
&mut self,
|
|
||||||
source: InferenceTyDiagnosticSource,
|
|
||||||
diagnostics: Vec<TyLoweringDiagnostic>,
|
|
||||||
) {
|
|
||||||
self.result.diagnostics.extend(
|
|
||||||
diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_ty_lowering<R>(
|
fn with_ty_lowering<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
types_map: &TypesMap,
|
types_map: &TypesMap,
|
||||||
types_source: InferenceTyDiagnosticSource,
|
types_source: InferenceTyDiagnosticSource,
|
||||||
f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
|
f: impl FnOnce(&mut TyLoweringContext<'_>) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
let mut ctx = crate::lower::TyLoweringContext::new(
|
let mut ctx = TyLoweringContext::new(
|
||||||
self.db,
|
self.db,
|
||||||
&self.resolver,
|
&self.resolver,
|
||||||
types_map,
|
types_map,
|
||||||
self.owner.into(),
|
self.owner.into(),
|
||||||
|
&self.diagnostics,
|
||||||
|
types_source,
|
||||||
);
|
);
|
||||||
let result = f(&mut ctx);
|
f(&mut ctx)
|
||||||
self.push_ty_diagnostics(types_source, ctx.diagnostics);
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_body_ty_lowering<R>(
|
fn with_body_ty_lowering<R>(&mut self, f: impl FnOnce(&mut TyLoweringContext<'_>) -> R) -> R {
|
||||||
&mut self,
|
|
||||||
f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
|
|
||||||
) -> R {
|
|
||||||
self.with_ty_lowering(&self.body.types, InferenceTyDiagnosticSource::Body, f)
|
self.with_ty_lowering(&self.body.types, InferenceTyDiagnosticSource::Body, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1451,51 +1459,55 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option<VariantId>) {
|
fn resolve_variant(
|
||||||
|
&mut self,
|
||||||
|
node: ExprOrPatId,
|
||||||
|
path: Option<&Path>,
|
||||||
|
value_ns: bool,
|
||||||
|
) -> (Ty, Option<VariantId>) {
|
||||||
let path = match path {
|
let path = match path {
|
||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
None => return (self.err_ty(), None),
|
None => return (self.err_ty(), None),
|
||||||
};
|
};
|
||||||
let mut ctx = crate::lower::TyLoweringContext::new(
|
let mut ctx = TyLoweringContext::new(
|
||||||
self.db,
|
self.db,
|
||||||
&self.resolver,
|
&self.resolver,
|
||||||
&self.body.types,
|
&self.body.types,
|
||||||
self.owner.into(),
|
self.owner.into(),
|
||||||
|
&self.diagnostics,
|
||||||
|
InferenceTyDiagnosticSource::Body,
|
||||||
);
|
);
|
||||||
let (resolution, unresolved) = if value_ns {
|
let (resolution, unresolved) = if value_ns {
|
||||||
match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) {
|
let Some(res) = ctx.resolve_path_in_value_ns(path, node, HygieneId::ROOT) else {
|
||||||
Some(ResolveValueResult::ValueNs(value, _)) => match value {
|
return (self.err_ty(), None);
|
||||||
|
};
|
||||||
|
match res {
|
||||||
|
ResolveValueResult::ValueNs(value, _) => match value {
|
||||||
ValueNs::EnumVariantId(var) => {
|
ValueNs::EnumVariantId(var) => {
|
||||||
let substs = ctx.substs_from_path(path, var.into(), true);
|
let substs = ctx.substs_from_path(path, var.into(), true);
|
||||||
self.push_ty_diagnostics(
|
drop(ctx);
|
||||||
InferenceTyDiagnosticSource::Body,
|
|
||||||
ctx.diagnostics,
|
|
||||||
);
|
|
||||||
let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
|
let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
|
||||||
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
||||||
return (ty, Some(var.into()));
|
return (ty, Some(var.into()));
|
||||||
}
|
}
|
||||||
ValueNs::StructId(strukt) => {
|
ValueNs::StructId(strukt) => {
|
||||||
let substs = ctx.substs_from_path(path, strukt.into(), true);
|
let substs = ctx.substs_from_path(path, strukt.into(), true);
|
||||||
self.push_ty_diagnostics(
|
drop(ctx);
|
||||||
InferenceTyDiagnosticSource::Body,
|
|
||||||
ctx.diagnostics,
|
|
||||||
);
|
|
||||||
let ty = self.db.ty(strukt.into());
|
let ty = self.db.ty(strukt.into());
|
||||||
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
||||||
return (ty, Some(strukt.into()));
|
return (ty, Some(strukt.into()));
|
||||||
}
|
}
|
||||||
ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
|
ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
|
||||||
_ => return (self.err_ty(), None),
|
_ => {
|
||||||
},
|
drop(ctx);
|
||||||
Some(ResolveValueResult::Partial(typens, unresolved, _)) => {
|
return (self.err_ty(), None);
|
||||||
(typens, Some(unresolved))
|
|
||||||
}
|
}
|
||||||
None => return (self.err_ty(), None),
|
},
|
||||||
|
ResolveValueResult::Partial(typens, unresolved, _) => (typens, Some(unresolved)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
|
match ctx.resolve_path_in_type_ns(path, node) {
|
||||||
Some((it, idx, _)) => (it, idx),
|
Some((it, idx)) => (it, idx),
|
||||||
None => return (self.err_ty(), None),
|
None => return (self.err_ty(), None),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1506,21 +1518,21 @@ impl<'a> InferenceContext<'a> {
|
||||||
return match resolution {
|
return match resolution {
|
||||||
TypeNs::AdtId(AdtId::StructId(strukt)) => {
|
TypeNs::AdtId(AdtId::StructId(strukt)) => {
|
||||||
let substs = ctx.substs_from_path(path, strukt.into(), true);
|
let substs = ctx.substs_from_path(path, strukt.into(), true);
|
||||||
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
drop(ctx);
|
||||||
let ty = self.db.ty(strukt.into());
|
let ty = self.db.ty(strukt.into());
|
||||||
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
||||||
forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
|
forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
|
||||||
}
|
}
|
||||||
TypeNs::AdtId(AdtId::UnionId(u)) => {
|
TypeNs::AdtId(AdtId::UnionId(u)) => {
|
||||||
let substs = ctx.substs_from_path(path, u.into(), true);
|
let substs = ctx.substs_from_path(path, u.into(), true);
|
||||||
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
drop(ctx);
|
||||||
let ty = self.db.ty(u.into());
|
let ty = self.db.ty(u.into());
|
||||||
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
||||||
forbid_unresolved_segments((ty, Some(u.into())), unresolved)
|
forbid_unresolved_segments((ty, Some(u.into())), unresolved)
|
||||||
}
|
}
|
||||||
TypeNs::EnumVariantId(var) => {
|
TypeNs::EnumVariantId(var) => {
|
||||||
let substs = ctx.substs_from_path(path, var.into(), true);
|
let substs = ctx.substs_from_path(path, var.into(), true);
|
||||||
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
drop(ctx);
|
||||||
let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
|
let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
|
||||||
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
||||||
forbid_unresolved_segments((ty, Some(var.into())), unresolved)
|
forbid_unresolved_segments((ty, Some(var.into())), unresolved)
|
||||||
|
@ -1531,6 +1543,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
|
let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
|
||||||
|
|
||||||
let Some(mut remaining_idx) = unresolved else {
|
let Some(mut remaining_idx) = unresolved else {
|
||||||
|
drop(ctx);
|
||||||
return self.resolve_variant_on_alias(ty, None, mod_path);
|
return self.resolve_variant_on_alias(ty, None, mod_path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1538,6 +1551,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
|
|
||||||
// We need to try resolving unresolved segments one by one because each may resolve
|
// We need to try resolving unresolved segments one by one because each may resolve
|
||||||
// to a projection, which `TyLoweringContext` cannot handle on its own.
|
// to a projection, which `TyLoweringContext` cannot handle on its own.
|
||||||
|
let mut tried_resolving_once = false;
|
||||||
while !remaining_segments.is_empty() {
|
while !remaining_segments.is_empty() {
|
||||||
let resolved_segment = path.segments().get(remaining_idx - 1).unwrap();
|
let resolved_segment = path.segments().get(remaining_idx - 1).unwrap();
|
||||||
let current_segment = remaining_segments.take(1);
|
let current_segment = remaining_segments.take(1);
|
||||||
|
@ -1558,18 +1572,27 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tried_resolving_once {
|
||||||
|
// FIXME: with `inherent_associated_types` this is allowed, but our `lower_partly_resolved_path()`
|
||||||
|
// will need to be updated to err at the correct segment.
|
||||||
|
//
|
||||||
|
// We need to stop here because otherwise the segment index passed to `lower_partly_resolved_path()`
|
||||||
|
// will be incorrect, and that can mess up error reporting.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// `lower_partly_resolved_path()` returns `None` as type namespace unless
|
// `lower_partly_resolved_path()` returns `None` as type namespace unless
|
||||||
// `remaining_segments` is empty, which is never the case here. We don't know
|
// `remaining_segments` is empty, which is never the case here. We don't know
|
||||||
// which namespace the new `ty` is in until normalized anyway.
|
// which namespace the new `ty` is in until normalized anyway.
|
||||||
(ty, _) = ctx.lower_partly_resolved_path(
|
(ty, _) = ctx.lower_partly_resolved_path(
|
||||||
|
node,
|
||||||
resolution,
|
resolution,
|
||||||
resolved_segment,
|
resolved_segment,
|
||||||
current_segment,
|
current_segment,
|
||||||
|
(remaining_idx - 1) as u32,
|
||||||
false,
|
false,
|
||||||
&mut |_, _reason| {
|
|
||||||
// FIXME: Report an error.
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
tried_resolving_once = true;
|
||||||
|
|
||||||
ty = self.table.insert_type_vars(ty);
|
ty = self.table.insert_type_vars(ty);
|
||||||
ty = self.table.normalize_associated_types_in(ty);
|
ty = self.table.normalize_associated_types_in(ty);
|
||||||
|
@ -1582,7 +1605,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
remaining_idx += 1;
|
remaining_idx += 1;
|
||||||
remaining_segments = remaining_segments.skip(1);
|
remaining_segments = remaining_segments.skip(1);
|
||||||
}
|
}
|
||||||
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
drop(ctx);
|
||||||
|
|
||||||
let variant = ty.as_adt().and_then(|(id, _)| match id {
|
let variant = ty.as_adt().and_then(|(id, _)| match id {
|
||||||
AdtId::StructId(s) => Some(VariantId::StructId(s)),
|
AdtId::StructId(s) => Some(VariantId::StructId(s)),
|
||||||
|
@ -1601,7 +1624,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
};
|
};
|
||||||
let substs =
|
let substs =
|
||||||
ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None);
|
ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None);
|
||||||
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
drop(ctx);
|
||||||
let ty = self.db.ty(it.into());
|
let ty = self.db.ty(it.into());
|
||||||
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
||||||
|
|
||||||
|
|
128
crates/hir-ty/src/infer/diagnostics.rs
Normal file
128
crates/hir-ty/src/infer/diagnostics.rs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
//! This file contains the [`Diagnostics`] type used during inference,
|
||||||
|
//! and a wrapper around [`TyLoweringContext`] ([`InferenceTyLoweringContext`]) that replaces
|
||||||
|
//! it and takes care of diagnostics in inference.
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use hir_def::body::HygieneId;
|
||||||
|
use hir_def::hir::ExprOrPatId;
|
||||||
|
use hir_def::path::{Path, PathSegment, PathSegments};
|
||||||
|
use hir_def::resolver::{ResolveValueResult, Resolver, TypeNs};
|
||||||
|
use hir_def::type_ref::TypesMap;
|
||||||
|
use hir_def::TypeOwnerId;
|
||||||
|
|
||||||
|
use crate::db::HirDatabase;
|
||||||
|
use crate::{
|
||||||
|
InferenceDiagnostic, InferenceTyDiagnosticSource, Ty, TyLoweringContext, TyLoweringDiagnostic,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unfortunately, this struct needs to use interior mutability (but we encapsulate it)
|
||||||
|
// because when lowering types and paths we hold a `TyLoweringContext` that holds a reference
|
||||||
|
// to our resolver and so we cannot have mutable reference, but we really want to have
|
||||||
|
// ability to dispatch diagnostics during this work otherwise the code becomes a complete mess.
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub(super) struct Diagnostics(RefCell<Vec<InferenceDiagnostic>>);
|
||||||
|
|
||||||
|
impl Diagnostics {
|
||||||
|
pub(super) fn push(&self, diagnostic: InferenceDiagnostic) {
|
||||||
|
self.0.borrow_mut().push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_ty_diagnostics(
|
||||||
|
&self,
|
||||||
|
source: InferenceTyDiagnosticSource,
|
||||||
|
diagnostics: Vec<TyLoweringDiagnostic>,
|
||||||
|
) {
|
||||||
|
self.0.borrow_mut().extend(
|
||||||
|
diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn finish(self) -> Vec<InferenceDiagnostic> {
|
||||||
|
self.0.into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct InferenceTyLoweringContext<'a> {
|
||||||
|
ctx: TyLoweringContext<'a>,
|
||||||
|
diagnostics: &'a Diagnostics,
|
||||||
|
source: InferenceTyDiagnosticSource,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> InferenceTyLoweringContext<'a> {
|
||||||
|
pub(super) fn new(
|
||||||
|
db: &'a dyn HirDatabase,
|
||||||
|
resolver: &'a Resolver,
|
||||||
|
types_map: &'a TypesMap,
|
||||||
|
owner: TypeOwnerId,
|
||||||
|
diagnostics: &'a Diagnostics,
|
||||||
|
source: InferenceTyDiagnosticSource,
|
||||||
|
) -> Self {
|
||||||
|
Self { ctx: TyLoweringContext::new(db, resolver, types_map, owner), diagnostics, source }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn resolve_path_in_type_ns(
|
||||||
|
&mut self,
|
||||||
|
path: &Path,
|
||||||
|
node: ExprOrPatId,
|
||||||
|
) -> Option<(TypeNs, Option<usize>)> {
|
||||||
|
let diagnostics = self.diagnostics;
|
||||||
|
self.ctx.resolve_path_in_type_ns(path, &mut |_, diag| {
|
||||||
|
diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn resolve_path_in_value_ns(
|
||||||
|
&mut self,
|
||||||
|
path: &Path,
|
||||||
|
node: ExprOrPatId,
|
||||||
|
hygiene_id: HygieneId,
|
||||||
|
) -> Option<ResolveValueResult> {
|
||||||
|
let diagnostics = self.diagnostics;
|
||||||
|
self.ctx.resolve_path_in_value_ns(path, hygiene_id, &mut |_, diag| {
|
||||||
|
diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn lower_partly_resolved_path(
|
||||||
|
&mut self,
|
||||||
|
node: ExprOrPatId,
|
||||||
|
resolution: TypeNs,
|
||||||
|
resolved_segment: PathSegment<'_>,
|
||||||
|
remaining_segments: PathSegments<'_>,
|
||||||
|
resolved_segment_idx: u32,
|
||||||
|
infer_args: bool,
|
||||||
|
) -> (Ty, Option<TypeNs>) {
|
||||||
|
let diagnostics = self.diagnostics;
|
||||||
|
self.ctx.lower_partly_resolved_path(
|
||||||
|
resolution,
|
||||||
|
resolved_segment,
|
||||||
|
remaining_segments,
|
||||||
|
resolved_segment_idx,
|
||||||
|
infer_args,
|
||||||
|
&mut |_, diag| diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag }),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for InferenceTyLoweringContext<'a> {
|
||||||
|
type Target = TyLoweringContext<'a>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.ctx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for InferenceTyLoweringContext<'_> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.ctx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for InferenceTyLoweringContext<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.diagnostics
|
||||||
|
.push_ty_diagnostics(self.source, std::mem::take(&mut self.ctx.diagnostics));
|
||||||
|
}
|
||||||
|
}
|
|
@ -531,7 +531,7 @@ impl InferenceContext<'_> {
|
||||||
(params, ret_ty)
|
(params, ret_ty)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.result.diagnostics.push(InferenceDiagnostic::ExpectedFunction {
|
self.push_diagnostic(InferenceDiagnostic::ExpectedFunction {
|
||||||
call_expr: tgt_expr,
|
call_expr: tgt_expr,
|
||||||
found: callee_ty.clone(),
|
found: callee_ty.clone(),
|
||||||
});
|
});
|
||||||
|
@ -707,7 +707,7 @@ impl InferenceContext<'_> {
|
||||||
self.result.standard_types.never.clone()
|
self.result.standard_types.never.clone()
|
||||||
}
|
}
|
||||||
Expr::RecordLit { path, fields, spread, .. } => {
|
Expr::RecordLit { path, fields, spread, .. } => {
|
||||||
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
|
let (ty, def_id) = self.resolve_variant(tgt_expr.into(), path.as_deref(), false);
|
||||||
|
|
||||||
if let Some(t) = expected.only_has_type(&mut self.table) {
|
if let Some(t) = expected.only_has_type(&mut self.table) {
|
||||||
self.unify(&ty, &t);
|
self.unify(&ty, &t);
|
||||||
|
@ -1816,9 +1816,10 @@ impl InferenceContext<'_> {
|
||||||
if !is_public {
|
if !is_public {
|
||||||
if let Either::Left(field) = field_id {
|
if let Either::Left(field) = field_id {
|
||||||
// FIXME: Merge this diagnostic into UnresolvedField?
|
// FIXME: Merge this diagnostic into UnresolvedField?
|
||||||
self.result
|
self.push_diagnostic(InferenceDiagnostic::PrivateField {
|
||||||
.diagnostics
|
expr: tgt_expr,
|
||||||
.push(InferenceDiagnostic::PrivateField { expr: tgt_expr, field });
|
field,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty
|
ty
|
||||||
|
@ -1835,7 +1836,7 @@ impl InferenceContext<'_> {
|
||||||
VisibleFromModule::Filter(self.resolver.module()),
|
VisibleFromModule::Filter(self.resolver.module()),
|
||||||
name,
|
name,
|
||||||
);
|
);
|
||||||
self.result.diagnostics.push(InferenceDiagnostic::UnresolvedField {
|
self.push_diagnostic(InferenceDiagnostic::UnresolvedField {
|
||||||
expr: tgt_expr,
|
expr: tgt_expr,
|
||||||
receiver: receiver_ty.clone(),
|
receiver: receiver_ty.clone(),
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
|
@ -1927,7 +1928,7 @@ impl InferenceContext<'_> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
self.result.diagnostics.push(InferenceDiagnostic::UnresolvedMethodCall {
|
self.push_diagnostic(InferenceDiagnostic::UnresolvedMethodCall {
|
||||||
expr: tgt_expr,
|
expr: tgt_expr,
|
||||||
receiver: receiver_ty.clone(),
|
receiver: receiver_ty.clone(),
|
||||||
name: method_name.clone(),
|
name: method_name.clone(),
|
||||||
|
|
|
@ -35,7 +35,7 @@ impl InferenceContext<'_> {
|
||||||
ellipsis: Option<u32>,
|
ellipsis: Option<u32>,
|
||||||
subs: &[PatId],
|
subs: &[PatId],
|
||||||
) -> Ty {
|
) -> Ty {
|
||||||
let (ty, def) = self.resolve_variant(path, true);
|
let (ty, def) = self.resolve_variant(id.into(), path, true);
|
||||||
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
|
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
|
||||||
if let Some(variant) = def {
|
if let Some(variant) = def {
|
||||||
self.write_variant_resolution(id.into(), variant);
|
self.write_variant_resolution(id.into(), variant);
|
||||||
|
@ -115,7 +115,7 @@ impl InferenceContext<'_> {
|
||||||
id: PatId,
|
id: PatId,
|
||||||
subs: impl ExactSizeIterator<Item = (Name, PatId)>,
|
subs: impl ExactSizeIterator<Item = (Name, PatId)>,
|
||||||
) -> Ty {
|
) -> Ty {
|
||||||
let (ty, def) = self.resolve_variant(path, false);
|
let (ty, def) = self.resolve_variant(id.into(), path, false);
|
||||||
if let Some(variant) = def {
|
if let Some(variant) = def {
|
||||||
self.write_variant_resolution(id.into(), variant);
|
self.write_variant_resolution(id.into(), variant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::{
|
||||||
builder::ParamKind,
|
builder::ParamKind,
|
||||||
consteval, error_lifetime,
|
consteval, error_lifetime,
|
||||||
generics::generics,
|
generics::generics,
|
||||||
|
infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
|
||||||
method_resolution::{self, VisibleFromModule},
|
method_resolution::{self, VisibleFromModule},
|
||||||
to_chalk_trait_id, InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty,
|
to_chalk_trait_id, InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty,
|
||||||
TyBuilder, TyExt, TyKind, ValueTyDefId,
|
TyBuilder, TyExt, TyKind, ValueTyDefId,
|
||||||
|
@ -147,36 +148,38 @@ impl InferenceContext<'_> {
|
||||||
path: &Path,
|
path: &Path,
|
||||||
id: ExprOrPatId,
|
id: ExprOrPatId,
|
||||||
) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
|
) -> 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`.
|
// Don't use `self.make_ty()` here as we need `orig_ns`.
|
||||||
let mut ctx = crate::lower::TyLoweringContext::new(
|
let mut ctx = TyLoweringContext::new(
|
||||||
self.db,
|
self.db,
|
||||||
&self.resolver,
|
&self.resolver,
|
||||||
&self.body.types,
|
&self.body.types,
|
||||||
self.owner.into(),
|
self.owner.into(),
|
||||||
|
&self.diagnostics,
|
||||||
|
InferenceTyDiagnosticSource::Body,
|
||||||
);
|
);
|
||||||
|
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
|
||||||
|
let last = path.segments().last()?;
|
||||||
|
|
||||||
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
|
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
|
||||||
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);
|
||||||
|
|
||||||
let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
|
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, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
|
||||||
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
drop(ctx);
|
||||||
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)))?
|
||||||
} else {
|
} else {
|
||||||
let hygiene = self.body.expr_or_pat_path_hygiene(id);
|
let hygiene = self.body.expr_or_pat_path_hygiene(id);
|
||||||
// FIXME: report error, unresolved first path segment
|
// FIXME: report error, unresolved first path segment
|
||||||
let value_or_partial =
|
let value_or_partial = ctx.resolve_path_in_value_ns(path, id, hygiene)?;
|
||||||
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene)?;
|
drop(ctx);
|
||||||
|
|
||||||
match value_or_partial {
|
match value_or_partial {
|
||||||
ResolveValueResult::ValueNs(it, _) => (it, None),
|
ResolveValueResult::ValueNs(it, _) => (it, None),
|
||||||
ResolveValueResult::Partial(def, remaining_index, _) => self
|
ResolveValueResult::Partial(def, remaining_index, _) => self
|
||||||
.resolve_assoc_item(def, path, remaining_index, id)
|
.resolve_assoc_item(id, def, path, remaining_index, id)
|
||||||
.map(|(it, substs)| (it, Some(substs)))?,
|
.map(|(it, substs)| (it, Some(substs)))?,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -212,6 +215,7 @@ impl InferenceContext<'_> {
|
||||||
|
|
||||||
fn resolve_assoc_item(
|
fn resolve_assoc_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
node: ExprOrPatId,
|
||||||
def: TypeNs,
|
def: TypeNs,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
remaining_index: usize,
|
remaining_index: usize,
|
||||||
|
@ -260,17 +264,23 @@ impl InferenceContext<'_> {
|
||||||
// as Iterator>::Item::default`)
|
// as Iterator>::Item::default`)
|
||||||
let remaining_segments_for_ty =
|
let remaining_segments_for_ty =
|
||||||
remaining_segments.take(remaining_segments.len() - 1);
|
remaining_segments.take(remaining_segments.len() - 1);
|
||||||
let (ty, _) = self.with_body_ty_lowering(|ctx| {
|
let mut ctx = TyLoweringContext::new(
|
||||||
ctx.lower_partly_resolved_path(
|
self.db,
|
||||||
|
&self.resolver,
|
||||||
|
&self.body.types,
|
||||||
|
self.owner.into(),
|
||||||
|
&self.diagnostics,
|
||||||
|
InferenceTyDiagnosticSource::Body,
|
||||||
|
);
|
||||||
|
let (ty, _) = ctx.lower_partly_resolved_path(
|
||||||
|
node,
|
||||||
def,
|
def,
|
||||||
resolved_segment,
|
resolved_segment,
|
||||||
remaining_segments_for_ty,
|
remaining_segments_for_ty,
|
||||||
|
(remaining_index - 1) as u32,
|
||||||
true,
|
true,
|
||||||
&mut |_, _reason| {
|
);
|
||||||
// FIXME: Report an error.
|
drop(ctx);
|
||||||
},
|
|
||||||
)
|
|
||||||
});
|
|
||||||
if ty.is_unknown() {
|
if ty.is_unknown() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,10 +88,10 @@ pub use infer::{
|
||||||
PointerCast,
|
PointerCast,
|
||||||
};
|
};
|
||||||
pub use interner::Interner;
|
pub use interner::Interner;
|
||||||
|
pub use lower::diagnostics::*;
|
||||||
pub use lower::{
|
pub use lower::{
|
||||||
associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode,
|
associated_type_shorthand_candidates, ImplTraitLoweringMode, ParamLoweringMode, TyDefId,
|
||||||
ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
|
TyLoweringContext, ValueTyDefId,
|
||||||
ValueTyDefId,
|
|
||||||
};
|
};
|
||||||
pub use mapping::{
|
pub use mapping::{
|
||||||
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
|
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
//! - Building the type for an item: This happens through the `ty` query.
|
//! - Building the type for an item: This happens through the `ty` query.
|
||||||
//!
|
//!
|
||||||
//! This usually involves resolving names, collecting generic arguments etc.
|
//! This usually involves resolving names, collecting generic arguments etc.
|
||||||
|
pub(crate) mod diagnostics;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::OnceCell,
|
cell::OnceCell,
|
||||||
iter, mem,
|
iter, mem,
|
||||||
|
@ -21,6 +23,7 @@ use chalk_ir::{
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
body::HygieneId,
|
||||||
builtin_type::BuiltinType,
|
builtin_type::BuiltinType,
|
||||||
data::adt::StructKind,
|
data::adt::StructKind,
|
||||||
expander::Expander,
|
expander::Expander,
|
||||||
|
@ -29,9 +32,9 @@ use hir_def::{
|
||||||
WherePredicateTypeTarget,
|
WherePredicateTypeTarget,
|
||||||
},
|
},
|
||||||
lang_item::LangItem,
|
lang_item::LangItem,
|
||||||
nameres::MacroSubNs,
|
nameres::{MacroSubNs, ResolvePathResultPrefixInfo},
|
||||||
path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
|
path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
|
||||||
resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
|
resolver::{HasResolver, LifetimeNs, ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||||
type_ref::{
|
type_ref::{
|
||||||
ConstRef, LifetimeRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound,
|
ConstRef, LifetimeRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound,
|
||||||
TypeRef, TypeRefId, TypesMap, TypesSourceMap,
|
TypeRef, TypeRefId, TypesMap, TypesSourceMap,
|
||||||
|
@ -59,6 +62,7 @@ use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
error_lifetime,
|
error_lifetime,
|
||||||
generics::{generics, trait_self_param_idx, Generics},
|
generics::{generics, trait_self_param_idx, Generics},
|
||||||
|
lower::diagnostics::*,
|
||||||
make_binders,
|
make_binders,
|
||||||
mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk},
|
mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk},
|
||||||
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
|
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
|
||||||
|
@ -102,31 +106,6 @@ impl ImplTraitLoweringState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type TypeSource = Either<TypeRefId, hir_def::type_ref::TypeSource>;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
||||||
pub struct TyLoweringDiagnostic {
|
|
||||||
pub source: TypeSource,
|
|
||||||
pub kind: TyLoweringDiagnosticKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
||||||
pub enum TyLoweringDiagnosticKind {
|
|
||||||
GenericArgsProhibited { segment: u32, reason: GenericArgsProhibitedReason },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum GenericArgsProhibitedReason {
|
|
||||||
Module,
|
|
||||||
TyParam,
|
|
||||||
SelfTy,
|
|
||||||
PrimitiveTy,
|
|
||||||
/// When there is a generic enum, within the expression `Enum::Variant`,
|
|
||||||
/// either `Enum` or `Variant` are allowed to have generic arguments, but not both.
|
|
||||||
// FIXME: This is not used now but it should be.
|
|
||||||
EnumVariant,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TyLoweringContext<'a> {
|
pub struct TyLoweringContext<'a> {
|
||||||
pub db: &'a dyn HirDatabase,
|
pub db: &'a dyn HirDatabase,
|
||||||
|
@ -536,8 +515,8 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
/// This is only for `generic_predicates_for_param`, where we can't just
|
/// This is only for `generic_predicates_for_param`, where we can't just
|
||||||
/// lower the self types of the predicates since that could lead to cycles.
|
/// lower the self types of the predicates since that could lead to cycles.
|
||||||
/// So we just check here if the `type_ref` resolves to a generic param, and which.
|
/// So we just check here if the `type_ref` resolves to a generic param, and which.
|
||||||
fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
|
fn lower_ty_only_param(&mut self, type_ref_id: TypeRefId) -> Option<TypeOrConstParamId> {
|
||||||
let type_ref = &self.types_map[type_ref];
|
let type_ref = &self.types_map[type_ref_id];
|
||||||
let path = match type_ref {
|
let path = match type_ref {
|
||||||
TypeRef::Path(path) => path,
|
TypeRef::Path(path) => path,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
@ -548,8 +527,10 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
if path.segments().len() > 1 {
|
if path.segments().len() > 1 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let resolution = match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
|
let resolution = match self
|
||||||
Some((it, None, _)) => it,
|
.resolve_path_in_type_ns(path, &mut Self::on_path_diagnostic_callback(type_ref_id))
|
||||||
|
{
|
||||||
|
Some((it, None)) => it,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
match resolution {
|
match resolution {
|
||||||
|
@ -584,11 +565,9 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
resolution: TypeNs,
|
resolution: TypeNs,
|
||||||
resolved_segment: PathSegment<'_>,
|
resolved_segment: PathSegment<'_>,
|
||||||
remaining_segments: PathSegments<'_>,
|
remaining_segments: PathSegments<'_>,
|
||||||
|
_resolved_segment_idx: u32,
|
||||||
infer_args: bool,
|
infer_args: bool,
|
||||||
on_prohibited_generics_for_resolved_segment: &mut dyn FnMut(
|
_on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
|
||||||
&mut Self,
|
|
||||||
GenericArgsProhibitedReason,
|
|
||||||
),
|
|
||||||
) -> (Ty, Option<TypeNs>) {
|
) -> (Ty, Option<TypeNs>) {
|
||||||
let ty = match resolution {
|
let ty = match resolution {
|
||||||
TypeNs::TraitId(trait_) => {
|
TypeNs::TraitId(trait_) => {
|
||||||
|
@ -655,15 +634,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
// FIXME(trait_alias): Implement trait alias.
|
// FIXME(trait_alias): Implement trait alias.
|
||||||
return (TyKind::Error.intern(Interner), None);
|
return (TyKind::Error.intern(Interner), None);
|
||||||
}
|
}
|
||||||
TypeNs::GenericParam(param_id) => {
|
TypeNs::GenericParam(param_id) => match self.type_param_mode {
|
||||||
if resolved_segment.args_and_bindings.is_some() {
|
|
||||||
on_prohibited_generics_for_resolved_segment(
|
|
||||||
self,
|
|
||||||
GenericArgsProhibitedReason::TyParam,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.type_param_mode {
|
|
||||||
ParamLoweringMode::Placeholder => {
|
ParamLoweringMode::Placeholder => {
|
||||||
TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
|
TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
|
||||||
}
|
}
|
||||||
|
@ -683,16 +654,8 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
|
TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.intern(Interner)
|
.intern(Interner),
|
||||||
}
|
|
||||||
TypeNs::SelfType(impl_id) => {
|
TypeNs::SelfType(impl_id) => {
|
||||||
if resolved_segment.args_and_bindings.is_some() {
|
|
||||||
on_prohibited_generics_for_resolved_segment(
|
|
||||||
self,
|
|
||||||
GenericArgsProhibitedReason::SelfTy,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let generics = self.generics().expect("impl should have generic param scope");
|
let generics = self.generics().expect("impl should have generic param scope");
|
||||||
|
|
||||||
match self.type_param_mode {
|
match self.type_param_mode {
|
||||||
|
@ -718,13 +681,6 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeNs::AdtSelfType(adt) => {
|
TypeNs::AdtSelfType(adt) => {
|
||||||
if resolved_segment.args_and_bindings.is_some() {
|
|
||||||
on_prohibited_generics_for_resolved_segment(
|
|
||||||
self,
|
|
||||||
GenericArgsProhibitedReason::SelfTy,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let generics = generics(self.db.upcast(), adt.into());
|
let generics = generics(self.db.upcast(), adt.into());
|
||||||
let substs = match self.type_param_mode {
|
let substs = match self.type_param_mode {
|
||||||
ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
|
ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
|
||||||
|
@ -737,12 +693,6 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
|
|
||||||
TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args),
|
TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args),
|
||||||
TypeNs::BuiltinType(it) => {
|
TypeNs::BuiltinType(it) => {
|
||||||
if resolved_segment.args_and_bindings.is_some() {
|
|
||||||
on_prohibited_generics_for_resolved_segment(
|
|
||||||
self,
|
|
||||||
GenericArgsProhibitedReason::PrimitiveTy,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
self.lower_path_inner(resolved_segment, it.into(), infer_args)
|
self.lower_path_inner(resolved_segment, it.into(), infer_args)
|
||||||
}
|
}
|
||||||
TypeNs::TypeAliasId(it) => {
|
TypeNs::TypeAliasId(it) => {
|
||||||
|
@ -754,6 +704,220 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
|
self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_type_ns_resolution(
|
||||||
|
&mut self,
|
||||||
|
resolution: &TypeNs,
|
||||||
|
resolved_segment: PathSegment<'_>,
|
||||||
|
resolved_segment_idx: usize,
|
||||||
|
on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
|
||||||
|
) {
|
||||||
|
let mut prohibit_generics_on_resolved = |reason| {
|
||||||
|
if resolved_segment.args_and_bindings.is_some() {
|
||||||
|
on_diagnostic(
|
||||||
|
self,
|
||||||
|
PathLoweringDiagnostic::GenericArgsProhibited {
|
||||||
|
segment: resolved_segment_idx as u32,
|
||||||
|
reason,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match resolution {
|
||||||
|
TypeNs::SelfType(_) => {
|
||||||
|
prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
|
||||||
|
}
|
||||||
|
TypeNs::GenericParam(_) => {
|
||||||
|
prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam)
|
||||||
|
}
|
||||||
|
TypeNs::AdtSelfType(_) => {
|
||||||
|
prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
|
||||||
|
}
|
||||||
|
TypeNs::BuiltinType(_) => {
|
||||||
|
prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy)
|
||||||
|
}
|
||||||
|
TypeNs::AdtId(_)
|
||||||
|
| TypeNs::EnumVariantId(_)
|
||||||
|
| TypeNs::TypeAliasId(_)
|
||||||
|
| TypeNs::TraitId(_)
|
||||||
|
| TypeNs::TraitAliasId(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_path_in_type_ns_fully(
|
||||||
|
&mut self,
|
||||||
|
path: &Path,
|
||||||
|
on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
|
||||||
|
) -> Option<TypeNs> {
|
||||||
|
let (res, unresolved) = self.resolve_path_in_type_ns(path, on_diagnostic)?;
|
||||||
|
if unresolved.is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_path_in_type_ns(
|
||||||
|
&mut self,
|
||||||
|
path: &Path,
|
||||||
|
on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
|
||||||
|
) -> Option<(TypeNs, Option<usize>)> {
|
||||||
|
let (resolution, remaining_index, _) =
|
||||||
|
self.resolver.resolve_path_in_type_ns(self.db.upcast(), path)?;
|
||||||
|
let segments = path.segments();
|
||||||
|
|
||||||
|
match path {
|
||||||
|
// `segments.is_empty()` can occur with `self`.
|
||||||
|
Path::Normal(..) if !segments.is_empty() => (),
|
||||||
|
_ => return Some((resolution, remaining_index)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let (module_segments, resolved_segment_idx, resolved_segment) = match remaining_index {
|
||||||
|
None => (
|
||||||
|
segments.strip_last(),
|
||||||
|
segments.len() - 1,
|
||||||
|
segments.last().expect("resolved path has at least one element"),
|
||||||
|
),
|
||||||
|
Some(i) => (segments.take(i - 1), i - 1, segments.get(i - 1).unwrap()),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i, mod_segment) in module_segments.iter().enumerate() {
|
||||||
|
if mod_segment.args_and_bindings.is_some() {
|
||||||
|
on_diagnostic(
|
||||||
|
self,
|
||||||
|
PathLoweringDiagnostic::GenericArgsProhibited {
|
||||||
|
segment: i as u32,
|
||||||
|
reason: GenericArgsProhibitedReason::Module,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.handle_type_ns_resolution(
|
||||||
|
&resolution,
|
||||||
|
resolved_segment,
|
||||||
|
resolved_segment_idx,
|
||||||
|
on_diagnostic,
|
||||||
|
);
|
||||||
|
|
||||||
|
Some((resolution, remaining_index))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_path_in_value_ns(
|
||||||
|
&mut self,
|
||||||
|
path: &Path,
|
||||||
|
hygiene_id: HygieneId,
|
||||||
|
on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
|
||||||
|
) -> Option<ResolveValueResult> {
|
||||||
|
let (res, prefix_info) = self.resolver.resolve_path_in_value_ns_with_prefix_info(
|
||||||
|
self.db.upcast(),
|
||||||
|
path,
|
||||||
|
hygiene_id,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let segments = path.segments();
|
||||||
|
match path {
|
||||||
|
// `segments.is_empty()` can occur with `self`.
|
||||||
|
Path::Normal(..) if !segments.is_empty() => (),
|
||||||
|
_ => return Some(res),
|
||||||
|
};
|
||||||
|
|
||||||
|
let (mod_segments, enum_segment) = match res {
|
||||||
|
ResolveValueResult::Partial(_, unresolved_segment, _) => {
|
||||||
|
(segments.take(unresolved_segment - 1), None)
|
||||||
|
}
|
||||||
|
ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
|
||||||
|
if prefix_info == ResolvePathResultPrefixInfo::Enum =>
|
||||||
|
{
|
||||||
|
(segments.strip_last_two(), segments.len().checked_sub(2))
|
||||||
|
}
|
||||||
|
ResolveValueResult::ValueNs(..) => (segments.strip_last(), None),
|
||||||
|
};
|
||||||
|
for (i, mod_segment) in mod_segments.iter().enumerate() {
|
||||||
|
if mod_segment.args_and_bindings.is_some() {
|
||||||
|
on_diagnostic(
|
||||||
|
self,
|
||||||
|
PathLoweringDiagnostic::GenericArgsProhibited {
|
||||||
|
segment: i as u32,
|
||||||
|
reason: GenericArgsProhibitedReason::Module,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(enum_segment) = enum_segment {
|
||||||
|
if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
|
||||||
|
&& segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
|
||||||
|
{
|
||||||
|
on_diagnostic(
|
||||||
|
self,
|
||||||
|
PathLoweringDiagnostic::GenericArgsProhibited {
|
||||||
|
segment: (enum_segment + 1) as u32,
|
||||||
|
reason: GenericArgsProhibitedReason::EnumVariant,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match &res {
|
||||||
|
ResolveValueResult::ValueNs(resolution, _) => {
|
||||||
|
let resolved_segment_idx =
|
||||||
|
segments.len().checked_sub(1).unwrap_or_else(|| panic!("{path:?}"));
|
||||||
|
let resolved_segment = segments.last().unwrap();
|
||||||
|
|
||||||
|
let mut prohibit_generics_on_resolved = |reason| {
|
||||||
|
if resolved_segment.args_and_bindings.is_some() {
|
||||||
|
on_diagnostic(
|
||||||
|
self,
|
||||||
|
PathLoweringDiagnostic::GenericArgsProhibited {
|
||||||
|
segment: resolved_segment_idx as u32,
|
||||||
|
reason,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match resolution {
|
||||||
|
ValueNs::ImplSelf(_) => {
|
||||||
|
prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy)
|
||||||
|
}
|
||||||
|
// FIXME: rustc generates E0107 (incorrect number of generic arguments) and not
|
||||||
|
// E0109 (generic arguments provided for a type that doesn't accept them) for
|
||||||
|
// consts and statics, presumably as a defense against future in which consts
|
||||||
|
// and statics can be generic, or just because it was easier for rustc implementors.
|
||||||
|
// That means we'll show the wrong error code. Because of us it's easier to do it
|
||||||
|
// this way :)
|
||||||
|
ValueNs::GenericParam(_) | ValueNs::ConstId(_) => {
|
||||||
|
prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const)
|
||||||
|
}
|
||||||
|
ValueNs::StaticId(_) => {
|
||||||
|
prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static)
|
||||||
|
}
|
||||||
|
ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::EnumVariantId(_) => {}
|
||||||
|
ValueNs::LocalBinding(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ResolveValueResult::Partial(resolution, unresolved_idx, _) => {
|
||||||
|
let resolved_segment_idx = unresolved_idx - 1;
|
||||||
|
let resolved_segment = segments.get(resolved_segment_idx).unwrap();
|
||||||
|
self.handle_type_ns_resolution(
|
||||||
|
resolution,
|
||||||
|
resolved_segment,
|
||||||
|
resolved_segment_idx,
|
||||||
|
on_diagnostic,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_path_diagnostic_callback(
|
||||||
|
type_ref: TypeRefId,
|
||||||
|
) -> impl FnMut(&mut Self, PathLoweringDiagnostic) {
|
||||||
|
move |this, diag| {
|
||||||
|
this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option<TypeNs>) {
|
pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option<TypeNs>) {
|
||||||
// Resolve the path (in type namespace)
|
// Resolve the path (in type namespace)
|
||||||
if let Some(type_ref) = path.type_anchor() {
|
if let Some(type_ref) = path.type_anchor() {
|
||||||
|
@ -761,8 +925,10 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
return self.lower_ty_relative_path(ty, res, path.segments());
|
return self.lower_ty_relative_path(ty, res, path.segments());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (resolution, remaining_index, _) =
|
let (resolution, remaining_index) = match self.resolve_path_in_type_ns(
|
||||||
match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
|
path,
|
||||||
|
&mut Self::on_path_diagnostic_callback(path_id.type_ref()),
|
||||||
|
) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => return (TyKind::Error.intern(Interner), None),
|
None => return (TyKind::Error.intern(Interner), None),
|
||||||
};
|
};
|
||||||
|
@ -774,38 +940,22 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
return (ty, None);
|
return (ty, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (module_segments, resolved_segment_idx, resolved_segment, remaining_segments) =
|
let (resolved_segment_idx, resolved_segment, remaining_segments) = match remaining_index {
|
||||||
match remaining_index {
|
|
||||||
None => (
|
None => (
|
||||||
path.segments().strip_last(),
|
|
||||||
path.segments().len() - 1,
|
path.segments().len() - 1,
|
||||||
path.segments().last().expect("resolved path has at least one element"),
|
path.segments().last().expect("resolved path has at least one element"),
|
||||||
PathSegments::EMPTY,
|
PathSegments::EMPTY,
|
||||||
),
|
),
|
||||||
Some(i) => (
|
Some(i) => (i - 1, path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
|
||||||
path.segments().take(i - 1),
|
|
||||||
i - 1,
|
|
||||||
path.segments().get(i - 1).unwrap(),
|
|
||||||
path.segments().skip(i),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.prohibit_generics(path_id, 0, module_segments, GenericArgsProhibitedReason::Module);
|
|
||||||
|
|
||||||
self.lower_partly_resolved_path(
|
self.lower_partly_resolved_path(
|
||||||
resolution,
|
resolution,
|
||||||
resolved_segment,
|
resolved_segment,
|
||||||
remaining_segments,
|
remaining_segments,
|
||||||
|
resolved_segment_idx as u32,
|
||||||
false,
|
false,
|
||||||
&mut |this, reason| {
|
&mut Self::on_path_diagnostic_callback(path_id.type_ref()),
|
||||||
this.push_diagnostic(
|
|
||||||
path_id.type_ref(),
|
|
||||||
TyLoweringDiagnosticKind::GenericArgsProhibited {
|
|
||||||
segment: resolved_segment_idx as u32,
|
|
||||||
reason,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1107,7 +1257,9 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
if segment.args_and_bindings.is_some() {
|
if segment.args_and_bindings.is_some() {
|
||||||
self.push_diagnostic(
|
self.push_diagnostic(
|
||||||
path_id.type_ref(),
|
path_id.type_ref(),
|
||||||
TyLoweringDiagnosticKind::GenericArgsProhibited { segment: idx, reason },
|
TyLoweringDiagnosticKind::PathDiagnostic(
|
||||||
|
PathLoweringDiagnostic::GenericArgsProhibited { segment: idx, reason },
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1119,7 +1271,10 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
explicit_self_ty: Ty,
|
explicit_self_ty: Ty,
|
||||||
) -> Option<TraitRef> {
|
) -> Option<TraitRef> {
|
||||||
let path = &self.types_map[path_id];
|
let path = &self.types_map[path_id];
|
||||||
let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? {
|
let resolved = match self.resolve_path_in_type_ns_fully(
|
||||||
|
path,
|
||||||
|
&mut Self::on_path_diagnostic_callback(path_id.type_ref()),
|
||||||
|
)? {
|
||||||
// FIXME(trait_alias): We need to handle trait alias here.
|
// FIXME(trait_alias): We need to handle trait alias here.
|
||||||
TypeNs::TraitId(tr) => tr,
|
TypeNs::TraitId(tr) => tr,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
|
36
crates/hir-ty/src/lower/diagnostics.rs
Normal file
36
crates/hir-ty/src/lower/diagnostics.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//! This files contains the declaration of diagnostics kinds for ty and path lowering.
|
||||||
|
|
||||||
|
use either::Either;
|
||||||
|
use hir_def::type_ref::TypeRefId;
|
||||||
|
|
||||||
|
type TypeSource = Either<TypeRefId, hir_def::type_ref::TypeSource>;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub struct TyLoweringDiagnostic {
|
||||||
|
pub source: TypeSource,
|
||||||
|
pub kind: TyLoweringDiagnosticKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum TyLoweringDiagnosticKind {
|
||||||
|
PathDiagnostic(PathLoweringDiagnostic),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum GenericArgsProhibitedReason {
|
||||||
|
Module,
|
||||||
|
TyParam,
|
||||||
|
SelfTy,
|
||||||
|
PrimitiveTy,
|
||||||
|
Const,
|
||||||
|
Static,
|
||||||
|
/// When there is a generic enum, within the expression `Enum::Variant`,
|
||||||
|
/// either `Enum` or `Variant` are allowed to have generic arguments, but not both.
|
||||||
|
// FIXME: This is not used now but it should be.
|
||||||
|
EnumVariant,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum PathLoweringDiagnostic {
|
||||||
|
GenericArgsProhibited { segment: u32, reason: GenericArgsProhibitedReason },
|
||||||
|
}
|
|
@ -15,12 +15,12 @@ use hir_expand::{name::Name, HirFileId, InFile};
|
||||||
use hir_ty::{
|
use hir_ty::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
|
diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
|
||||||
CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
|
CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, PathLoweringDiagnostic,
|
||||||
TyLoweringDiagnosticKind,
|
TyLoweringDiagnostic, TyLoweringDiagnosticKind,
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, HasGenericArgs},
|
ast::{self, HasGenericArgs},
|
||||||
AstPtr, SyntaxError, SyntaxNodePtr, TextRange,
|
match_ast, AstNode, AstPtr, SyntaxError, SyntaxNodePtr, TextRange,
|
||||||
};
|
};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
|
@ -674,6 +674,39 @@ impl AnyDiagnostic {
|
||||||
};
|
};
|
||||||
Self::ty_diagnostic(diag, source_map, db)?
|
Self::ty_diagnostic(diag, source_map, db)?
|
||||||
}
|
}
|
||||||
|
InferenceDiagnostic::PathDiagnostic { node, diag } => {
|
||||||
|
let source = expr_or_pat_syntax(*node)?;
|
||||||
|
let syntax = source.value.to_node(&db.parse_or_expand(source.file_id));
|
||||||
|
let path = match_ast! {
|
||||||
|
match (syntax.syntax()) {
|
||||||
|
ast::RecordExpr(it) => it.path()?,
|
||||||
|
ast::RecordPat(it) => it.path()?,
|
||||||
|
ast::TupleStructPat(it) => it.path()?,
|
||||||
|
ast::PathExpr(it) => it.path()?,
|
||||||
|
ast::PathPat(it) => it.path()?,
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Self::path_diagnostic(diag, source.with_value(path))?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_diagnostic(
|
||||||
|
diag: &PathLoweringDiagnostic,
|
||||||
|
path: InFile<ast::Path>,
|
||||||
|
) -> Option<AnyDiagnostic> {
|
||||||
|
Some(match diag {
|
||||||
|
&PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => {
|
||||||
|
let segment = hir_segment_to_ast_segment(&path.value, segment)?;
|
||||||
|
let args = if let Some(generics) = segment.generic_arg_list() {
|
||||||
|
AstPtr::new(&generics).wrap_left()
|
||||||
|
} else {
|
||||||
|
AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right()
|
||||||
|
};
|
||||||
|
let args = path.with_value(args);
|
||||||
|
GenericArgsProhibited { args, reason }.into()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,17 +726,10 @@ impl AnyDiagnostic {
|
||||||
Either::Right(source) => source,
|
Either::Right(source) => source,
|
||||||
};
|
};
|
||||||
let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id));
|
let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id));
|
||||||
Some(match diag.kind {
|
Some(match &diag.kind {
|
||||||
TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => {
|
TyLoweringDiagnosticKind::PathDiagnostic(diag) => {
|
||||||
let ast::Type::PathType(syntax) = syntax() else { return None };
|
let ast::Type::PathType(syntax) = syntax() else { return None };
|
||||||
let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?;
|
Self::path_diagnostic(diag, source.with_value(syntax.path()?))?
|
||||||
let args = if let Some(generics) = segment.generic_arg_list() {
|
|
||||||
AstPtr::new(&generics).wrap_left()
|
|
||||||
} else {
|
|
||||||
AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right()
|
|
||||||
};
|
|
||||||
let args = source.with_value(args);
|
|
||||||
GenericArgsProhibited { args, reason }.into()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,8 @@ fn describe_reason(reason: GenericArgsProhibitedReason) -> String {
|
||||||
return "you can specify generic arguments on either the enum or the variant, but not both"
|
return "you can specify generic arguments on either the enum or the variant, but not both"
|
||||||
.to_owned();
|
.to_owned();
|
||||||
}
|
}
|
||||||
|
GenericArgsProhibitedReason::Const => "constants",
|
||||||
|
GenericArgsProhibitedReason::Static => "statics",
|
||||||
};
|
};
|
||||||
format!("generic arguments are not allowed on {kind}")
|
format!("generic arguments are not allowed on {kind}")
|
||||||
}
|
}
|
||||||
|
@ -435,6 +437,144 @@ type T = bool<i32>;
|
||||||
impl Trait for () {
|
impl Trait for () {
|
||||||
type Assoc = i32<bool>;
|
type Assoc = i32<bool>;
|
||||||
// ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
|
// ^^^^^^ 💡 error: generic arguments are not allowed on builtin types
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn in_record_expr() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub struct Bar { pub field: i32 }
|
||||||
|
}
|
||||||
|
fn baz() {
|
||||||
|
let _ = foo::<()>::Bar { field: 0 };
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on modules
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn in_record_pat() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub struct Bar { field: i32 }
|
||||||
|
}
|
||||||
|
fn baz(v: foo::Bar) {
|
||||||
|
let foo::<()>::Bar { .. } = v;
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on modules
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn in_tuple_struct_pat() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub struct Bar(i32);
|
||||||
|
}
|
||||||
|
fn baz(v: foo::Bar) {
|
||||||
|
let foo::<()>::Bar(..) = v;
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on modules
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn in_path_pat() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub struct Bar;
|
||||||
|
}
|
||||||
|
fn baz(v: foo::Bar) {
|
||||||
|
let foo::<()>::Bar = v;
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on modules
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn in_path_expr() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub struct Bar;
|
||||||
|
}
|
||||||
|
fn baz() {
|
||||||
|
let _ = foo::<()>::Bar;
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on modules
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn const_and_static() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
const CONST: i32 = 0;
|
||||||
|
static STATIC: i32 = 0;
|
||||||
|
fn baz() {
|
||||||
|
let _ = CONST::<()>;
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on constants
|
||||||
|
let _ = STATIC::<()>;
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on statics
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enum_variant() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
enum Enum<A> {
|
||||||
|
Variant(A),
|
||||||
|
}
|
||||||
|
mod enum_ {
|
||||||
|
pub(super) use super::Enum::Variant as V;
|
||||||
|
}
|
||||||
|
fn baz() {
|
||||||
|
let v = Enum::<()>::Variant::<()>(());
|
||||||
|
// ^^^^^^ 💡 error: you can specify generic arguments on either the enum or the variant, but not both
|
||||||
|
let Enum::<()>::Variant::<()>(..) = v;
|
||||||
|
// ^^^^^^ 💡 error: you can specify generic arguments on either the enum or the variant, but not both
|
||||||
|
let _ = Enum::<()>::Variant(());
|
||||||
|
let _ = Enum::Variant::<()>(());
|
||||||
|
}
|
||||||
|
fn foo() {
|
||||||
|
use Enum::Variant;
|
||||||
|
let _ = Variant::<()>(());
|
||||||
|
let _ = enum_::V::<()>(());
|
||||||
|
let _ = enum_::<()>::V::<()>(());
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on modules
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dyn_trait() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub trait Trait {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
let _: &dyn foo::<()>::Trait;
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on modules
|
||||||
|
let _: &foo::<()>::Trait;
|
||||||
|
// ^^^^^^ 💡 error: generic arguments are not allowed on modules
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue