cl-typeck: Improve path resolution semantics, and DON'T REPARENT IMPLs
- Perform heirarchical resolution through "transparent" nodes - Reparenting impls broke relative path traversal entirely. To impl something, it must already be in scope anyway. - TODO: well-formedness checks?
This commit is contained in:
parent
6bf34fdff6
commit
70872d86f9
@ -28,6 +28,10 @@ impl Def<'_> {
|
|||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_transparent(&self) -> bool {
|
||||||
|
!matches!(self.kind, DefKind::Type(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod builder_functions {
|
mod builder_functions {
|
||||||
|
@ -19,13 +19,17 @@ impl<'p> Path<'p> {
|
|||||||
let Self { absolute, parts } = self;
|
let Self { absolute, parts } = self;
|
||||||
Some(Self { absolute, parts: parts.get(1..)? })
|
Some(Self { absolute, parts: parts.get(1..)? })
|
||||||
}
|
}
|
||||||
|
pub fn front(self) -> Option<Self> {
|
||||||
|
let Self { absolute, parts } = self;
|
||||||
|
Some(Self { absolute, parts: parts.get(..1)? })
|
||||||
|
}
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.parts.is_empty()
|
self.parts.is_empty()
|
||||||
}
|
}
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.parts.len()
|
self.parts.len()
|
||||||
}
|
}
|
||||||
pub fn front(&self) -> Option<&PathPart> {
|
pub fn first(&self) -> Option<&PathPart> {
|
||||||
self.parts.first()
|
self.parts.first()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,18 +88,32 @@ impl<'a> Project<'a> {
|
|||||||
return self.get(path.relative(), self.root_of(within));
|
return self.get(path.relative(), self.root_of(within));
|
||||||
}
|
}
|
||||||
match path.as_ref() {
|
match path.as_ref() {
|
||||||
[] => Some((Some(within), None, path)),
|
[PathPart::SuperKw, ..] => self.get(path.pop_front()?, self.parent_of(within)?),
|
||||||
|
[PathPart::SelfTy, ..] => self.get(path.pop_front()?, self.selfty_of(within)?),
|
||||||
|
[PathPart::SelfKw, ..] => self.get(path.pop_front()?, within),
|
||||||
[PathPart::Ident(name)] => {
|
[PathPart::Ident(name)] => {
|
||||||
let (ty, val) = self[within].module.get(*name);
|
let (ty, val) = self[within].module.get(*name);
|
||||||
|
|
||||||
|
// Transparent nodes can be looked through in reverse
|
||||||
|
if self[within].is_transparent() {
|
||||||
|
let lookback = self.parent_of(within).and_then(|p| self.get(path, p));
|
||||||
|
if let Some((subty, subval, path)) = lookback {
|
||||||
|
return Some((ty.or(subty), val.or(subval), path));
|
||||||
|
}
|
||||||
|
}
|
||||||
Some((ty, val, path.pop_front()?))
|
Some((ty, val, path.pop_front()?))
|
||||||
}
|
}
|
||||||
[PathPart::Ident(name), ..] => {
|
[PathPart::Ident(name), ..] => {
|
||||||
let ty = self[within].module.get_type(*name)?;
|
// TODO: This is currently too permissive, and treats undecided nodes as if they're
|
||||||
|
// always transparent, among other issues.
|
||||||
|
let (tysub, _, _) = match self[within].is_transparent() {
|
||||||
|
true => self.get(path.front()?, within)?,
|
||||||
|
false => (None, None, path),
|
||||||
|
};
|
||||||
|
let ty = self[within].module.get_type(*name).or(tysub)?;
|
||||||
self.get(path.pop_front()?, ty)
|
self.get(path.pop_front()?, ty)
|
||||||
}
|
}
|
||||||
[PathPart::SelfTy, ..] => self.get(path.pop_front()?, self.selfty_of(within)?),
|
[] => Some((Some(within), None, path)),
|
||||||
[PathPart::SelfKw, ..] => self.get(path.pop_front()?, within),
|
|
||||||
[PathPart::SuperKw, ..] => self.get(path.pop_front()?, self.parent_of(within)?),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +122,7 @@ impl<'a> Project<'a> {
|
|||||||
pub fn get_type<'p>(&self, path: Path<'p>, within: DefID) -> Option<(DefID, Path<'p>)> {
|
pub fn get_type<'p>(&self, path: Path<'p>, within: DefID) -> Option<(DefID, Path<'p>)> {
|
||||||
if path.absolute {
|
if path.absolute {
|
||||||
self.get_type(path.relative(), self.root_of(within))
|
self.get_type(path.relative(), self.root_of(within))
|
||||||
} else if let Some(front) = path.front() {
|
} else if let Some(front) = path.first() {
|
||||||
let module = &self[within].module;
|
let module = &self[within].module;
|
||||||
match front {
|
match front {
|
||||||
PathPart::SelfKw => self.get_type(path.pop_front()?, within),
|
PathPart::SelfKw => self.get_type(path.pop_front()?, within),
|
||||||
@ -124,16 +138,6 @@ impl<'a> Project<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_value<'p>(&self, path: Path<'p>, within: DefID) -> Option<(DefID, Path<'p>)> {
|
|
||||||
match path.front()? {
|
|
||||||
PathPart::Ident(name) => Some((
|
|
||||||
self[within].module.values.get(name).copied()?,
|
|
||||||
path.pop_front()?,
|
|
||||||
)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inserts the type returned by the provided closure iff the TypeKind doesn't already exist
|
/// Inserts the type returned by the provided closure iff the TypeKind doesn't already exist
|
||||||
///
|
///
|
||||||
/// Assumes `kind` uniquely identifies the type!
|
/// Assumes `kind` uniquely identifies the type!
|
||||||
|
@ -271,7 +271,6 @@ impl<'a> TypeResolvable<'a> for &'a Impl {
|
|||||||
}
|
}
|
||||||
.map_err(|_| "Unresolved type in impl target")?;
|
.map_err(|_| "Unresolved type in impl target")?;
|
||||||
|
|
||||||
prj[id].module.parent = Some(target);
|
|
||||||
match prj.pool.get_many_mut([id, target]) {
|
match prj.pool.get_many_mut([id, target]) {
|
||||||
// TODO: Better error handling
|
// TODO: Better error handling
|
||||||
Err(_) => Err(concat!(
|
Err(_) => Err(concat!(
|
||||||
|
Loading…
Reference in New Issue
Block a user