Skip to content

Commit

Permalink
Merge pull request #18541 from ChayimFriedman2/different-generic-args
Browse files Browse the repository at this point in the history
feat: Complete diagnostics in ty lowering groundwork and serve a first diagnostic 🎉
  • Loading branch information
Veykril authored Dec 4, 2024
2 parents 26bc01d + 21ad3b5 commit 39fd171
Show file tree
Hide file tree
Showing 34 changed files with 1,549 additions and 233 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions crates/hir-def/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{
path::{ModPath, Path},
src::HasSource,
type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
BlockId, DefWithBodyId, HasModule, Lookup,
BlockId, DefWithBodyId, HasModule, Lookup, SyntheticSyntax,
};

/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
Expand Down Expand Up @@ -141,7 +141,7 @@ pub struct BodySourceMap {
field_map_back: FxHashMap<ExprId, FieldSource>,
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,

types: TypesSourceMap,
pub types: TypesSourceMap,

// FIXME: Make this a sane struct.
template_map: Option<
Expand All @@ -160,9 +160,6 @@ pub struct BodySourceMap {
diagnostics: Vec<BodyDiagnostic>,
}

#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
pub struct SyntheticSyntax;

#[derive(Debug, Eq, PartialEq)]
pub enum BodyDiagnostic {
InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-def/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ impl ImplData {

let item_tree = tree_id.item_tree(db);
let impl_def = &item_tree[tree_id.value];
let target_trait = impl_def.target_trait.clone();
let target_trait = impl_def.target_trait;
let self_ty = impl_def.self_ty;
let is_negative = impl_def.is_negative;
let is_unsafe = impl_def.is_unsafe;
Expand Down
27 changes: 19 additions & 8 deletions crates/hir-def/src/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use crate::{
nameres::{DefMap, MacroSubNs},
path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
type_ref::{
ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap,
TypesSourceMap,
ArrayType, ConstRef, FnType, LifetimeRef, PathId, RefType, TypeBound, TypeRef, TypeRefId,
TypesMap, TypesSourceMap,
},
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
Expand Down Expand Up @@ -224,6 +224,11 @@ impl GenericParams {
self.len() == 0
}

#[inline]
pub fn no_predicates(&self) -> bool {
self.where_predicates.is_empty()
}

#[inline]
pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
self.where_predicates.iter()
Expand Down Expand Up @@ -874,14 +879,20 @@ fn copy_type_bound(
to: &mut TypesMap,
to_source_map: &mut TypesSourceMap,
) -> TypeBound {
let mut copy_path_id = |path: PathId| {
let new_path = copy_path(&from[path], from, from_source_map, to, to_source_map);
let new_path_id = to.types.alloc(TypeRef::Path(new_path));
if let Some(&ptr) = from_source_map.types_map_back.get(path.type_ref()) {
to_source_map.types_map_back.insert(new_path_id, ptr);
}
PathId::from_type_ref_unchecked(new_path_id)
};

match bound {
TypeBound::Path(path, modifier) => {
TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier)
&TypeBound::Path(path, modifier) => TypeBound::Path(copy_path_id(path), modifier),
TypeBound::ForLifetime(lifetimes, path) => {
TypeBound::ForLifetime(lifetimes.clone(), copy_path_id(*path))
}
TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime(
lifetimes.clone(),
copy_path(path, from, from_source_map, to, to_source_map),
),
TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
TypeBound::Error => TypeBound::Error,
Expand Down
86 changes: 64 additions & 22 deletions crates/hir-def/src/hir/type_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
hir::Literal,
lower::LowerCtx,
path::{GenericArg, Path},
SyntheticSyntax,
};

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
Expand Down Expand Up @@ -91,19 +92,37 @@ impl Rawness {
}
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
/// A `TypeRefId` that is guaranteed to always be `TypeRef::Path`. We use this for things like
/// impl's trait, that are always paths but need to be traced back to source code.
pub struct PathId(TypeRefId);

impl PathId {
#[inline]
pub fn from_type_ref_unchecked(type_ref: TypeRefId) -> Self {
Self(type_ref)
}

#[inline]
pub fn type_ref(self) -> TypeRefId {
self.0
}
}

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct TraitRef {
pub path: Path,
pub path: PathId,
}

impl TraitRef {
/// Converts an `ast::PathType` to a `hir::TraitRef`.
pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> Option<Self> {
// FIXME: Use `Path::from_src`
match node {
ast::Type::PathType(path) => {
path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path })
}
match &node {
ast::Type::PathType(path) => path
.path()
.and_then(|it| ctx.lower_path(it))
.map(|path| TraitRef { path: ctx.alloc_path(path, AstPtr::new(&node)) }),
_ => None,
}
}
Expand Down Expand Up @@ -173,11 +192,24 @@ impl TypesMap {
impl Index<TypeRefId> for TypesMap {
type Output = TypeRef;

#[inline]
fn index(&self, index: TypeRefId) -> &Self::Output {
&self.types[index]
}
}

impl Index<PathId> for TypesMap {
type Output = Path;

#[inline]
fn index(&self, index: PathId) -> &Self::Output {
let TypeRef::Path(path) = &self[index.type_ref()] else {
unreachable!("`PathId` always points to `TypeRef::Path`");
};
path
}
}

pub type TypePtr = AstPtr<ast::Type>;
pub type TypeSource = InFile<TypePtr>;

Expand All @@ -187,6 +219,12 @@ pub struct TypesSourceMap {
}

impl TypesSourceMap {
pub const EMPTY: Self = Self { types_map_back: ArenaMap::new() };

pub fn type_syntax(&self, id: TypeRefId) -> Result<TypeSource, SyntheticSyntax> {
self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax)
}

pub(crate) fn shrink_to_fit(&mut self) {
let TypesSourceMap { types_map_back } = self;
types_map_back.shrink_to_fit();
Expand Down Expand Up @@ -214,15 +252,15 @@ impl LifetimeRef {

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TypeBound {
Path(Path, TraitBoundModifier),
ForLifetime(Box<[Name]>, Path),
Path(PathId, TraitBoundModifier),
ForLifetime(Box<[Name]>, PathId),
Lifetime(LifetimeRef),
Use(Box<[UseArgRef]>),
Error,
}

#[cfg(target_pointer_width = "64")]
const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()];
const _: [(); 24] = [(); ::std::mem::size_of::<TypeBound>()];

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum UseArgRef {
Expand Down Expand Up @@ -365,8 +403,8 @@ impl TypeRef {
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in bounds {
match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f, map)
&TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
go_path(&map[path], f, map)
}
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
}
Expand Down Expand Up @@ -397,8 +435,8 @@ impl TypeRef {
}
for bound in binding.bounds.iter() {
match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f, map)
&TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
go_path(&map[path], f, map)
}
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
}
Expand All @@ -425,16 +463,18 @@ pub(crate) fn type_bounds_from_ast(

impl TypeBound {
pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::TypeBound) -> Self {
let mut lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?);
let mut lower_path_type = |path_type: &ast::PathType| ctx.lower_path(path_type.path()?);

match node.kind() {
ast::TypeBoundKind::PathType(path_type) => {
let m = match node.question_mark_token() {
Some(_) => TraitBoundModifier::Maybe,
None => TraitBoundModifier::None,
};
lower_path_type(path_type)
.map(|p| TypeBound::Path(p, m))
lower_path_type(&path_type)
.map(|p| {
TypeBound::Path(ctx.alloc_path(p, AstPtr::new(&path_type).upcast()), m)
})
.unwrap_or(TypeBound::Error)
}
ast::TypeBoundKind::ForType(for_type) => {
Expand All @@ -445,12 +485,14 @@ impl TypeBound {
.collect(),
None => Box::default(),
};
let path = for_type.ty().and_then(|ty| match ty {
ast::Type::PathType(path_type) => lower_path_type(path_type),
let path = for_type.ty().and_then(|ty| match &ty {
ast::Type::PathType(path_type) => lower_path_type(path_type).map(|p| (p, ty)),
_ => None,
});
match path {
Some(p) => TypeBound::ForLifetime(lt_refs, p),
Some((p, ty)) => {
TypeBound::ForLifetime(lt_refs, ctx.alloc_path(p, AstPtr::new(&ty)))
}
None => TypeBound::Error,
}
}
Expand All @@ -470,10 +512,10 @@ impl TypeBound {
}
}

pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> {
pub fn as_path<'a>(&self, map: &'a TypesMap) -> Option<(&'a Path, TraitBoundModifier)> {
match self {
TypeBound::Path(p, m) => Some((p, m)),
TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
&TypeBound::Path(p, m) => Some((&map[p], m)),
&TypeBound::ForLifetime(_, p) => Some((&map[p], TraitBoundModifier::None)),
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
}
}
Expand Down
9 changes: 5 additions & 4 deletions crates/hir-def/src/item_tree/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::{
lower::LowerCtx,
path::AssociatedTypeBinding,
type_ref::{
LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
LifetimeRef, PathId, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
TypesMap, TypesSourceMap,
},
visibility::RawVisibility,
Expand Down Expand Up @@ -514,7 +514,7 @@ impl<'a> Ctx<'a> {
};

let ret_type = if func.async_token().is_some() {
let future_impl = desugar_future_path(ret_type);
let future_impl = desugar_future_path(&mut body_ctx, ret_type);
let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None);
body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound])))
} else {
Expand Down Expand Up @@ -936,7 +936,7 @@ impl<'a> Ctx<'a> {
}
}

fn desugar_future_path(orig: TypeRefId) -> Path {
fn desugar_future_path(ctx: &mut LowerCtx<'_>, orig: TypeRefId) -> PathId {
let path = path![core::future::Future];
let mut generic_args: Vec<_> =
std::iter::repeat(None).take(path.segments().len() - 1).collect();
Expand All @@ -948,7 +948,8 @@ fn desugar_future_path(orig: TypeRefId) -> Path {
};
generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));

Path::from_known_path(path, generic_args)
let path = Path::from_known_path(path, generic_args);
PathId::from_type_ref_unchecked(ctx.alloc_type_ref_desugared(TypeRef::Path(path)))
}

enum HasImplicitSelf {
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-def/src/item_tree/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ impl Printer<'_> {
w!(self, "!");
}
if let Some(tr) = target_trait {
self.print_path(&tr.path, types_map);
self.print_path(&types_map[tr.path], types_map);
w!(self, " for ");
}
self.print_type_ref(*self_ty, types_map);
Expand Down
3 changes: 3 additions & 0 deletions crates/hir-def/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1535,3 +1535,6 @@ fn macro_call_as_call_id_with_eager(
pub struct UnresolvedMacro {
pub path: hir_expand::mod_path::ModPath,
}

#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
pub struct SyntheticSyntax;
6 changes: 5 additions & 1 deletion crates/hir-def/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use triomphe::Arc;
use crate::{
db::DefDatabase,
path::Path,
type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
type_ref::{PathId, TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
};

pub struct LowerCtx<'a> {
Expand Down Expand Up @@ -142,4 +142,8 @@ impl<'a> LowerCtx<'a> {
pub(crate) fn alloc_error_type(&mut self) -> TypeRefId {
self.types_map.types.alloc(TypeRef::Error)
}

pub(crate) fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId {
PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node))
}
}
12 changes: 11 additions & 1 deletion crates/hir-def/src/path.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
mod lower;
#[cfg(test)]
mod tests;

use std::{
fmt::{self, Display},
Expand All @@ -19,6 +21,8 @@ use syntax::ast;

pub use hir_expand::mod_path::{path, ModPath, PathKind};

pub use lower::hir_segment_to_ast_segment;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ImportAlias {
/// Unnamed alias, as in `use Foo as _;`
Expand Down Expand Up @@ -230,7 +234,7 @@ impl Path {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PathSegment<'a> {
pub name: &'a Name,
pub args_and_bindings: Option<&'a GenericArgs>,
Expand Down Expand Up @@ -274,6 +278,12 @@ impl<'a> PathSegments<'a> {
generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)),
}
}
pub fn strip_last(&self) -> PathSegments<'a> {
PathSegments {
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)),
}
}
pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
self.segments
.iter()
Expand Down
Loading

0 comments on commit 39fd171

Please sign in to comment.