Forbid <T>::foo syntax in mod paths

This commit is contained in:
Aleksey Kladov 2019-12-18 17:41:33 +01:00
parent 88c6109897
commit 04715cbe1c
7 changed files with 27 additions and 20 deletions

View file

@ -590,7 +590,7 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
}
ps.push(chain.into());
}
hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None,
hir::PathKind::DollarCrate(_) => return None,
}
ps.extend(path.segments().iter().map(|it| it.name.to_string().into()));
Some(ps)

View file

@ -15,7 +15,7 @@ use crate::{
db::DefDatabase,
expr::{Expr, ExprId, Pat, PatId},
nameres::{BuiltinShadowMode, CrateDefMap},
path::Path,
path::{ModPath, Path},
src::HasSource,
DefWithBodyId, HasModule, Lookup, ModuleId,
};
@ -44,7 +44,7 @@ impl Expander {
db.ast_id_map(self.current_file_id).ast_id(&macro_call),
);
if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) {
if let Some(path) = macro_call.path().and_then(|path| self.parse_mod_path(path)) {
if let Some(def) = self.resolve_path_as_macro(db, &path) {
let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id));
let file_id = call_id.as_file();
@ -81,9 +81,13 @@ impl Expander {
Path::from_src(path, &self.hygiene)
}
fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
fn parse_mod_path(&mut self, path: ast::Path) -> Option<ModPath> {
ModPath::from_src(path, &self.hygiene)
}
fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &ModPath) -> Option<MacroDefId> {
self.crate_def_map
.resolve_path(db, self.module.local_id, path.mod_path(), BuiltinShadowMode::Other)
.resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
.0
.take_macros()
}

View file

@ -145,11 +145,6 @@ impl CrateDefMap {
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
}
}
PathKind::Type(_) => {
// This is handled in `infer::infer_path_expr`
// The result returned here does not matter
return ResolvePathResult::empty(ReachedFixedPoint::Yes);
}
};
for (i, segment) in segments {

View file

@ -26,8 +26,6 @@ pub enum PathKind {
Crate,
/// Absolute path (::foo)
Abs,
/// Type based path like `<T>::foo`
Type(Box<TypeRef>),
/// `$crate` from macro expansion
DollarCrate(CrateId),
}
@ -84,6 +82,8 @@ impl ModPath {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path {
/// Type based path like `<T>::foo`
type_anchor: Option<Box<TypeRef>>,
mod_path: ModPath,
/// Invariant: the same len as self.path.segments
generic_args: Vec<Option<Arc<GenericArgs>>>,
@ -126,7 +126,7 @@ impl Path {
/// Converts an `ast::NameRef` into a single-identifier `Path`.
pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
Path { mod_path: name_ref.as_name().into(), generic_args: vec![None] }
Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] }
}
/// `true` if this path is just a standalone `self`
@ -138,6 +138,10 @@ impl Path {
&self.mod_path.kind
}
pub fn type_anchor(&self) -> Option<&TypeRef> {
self.type_anchor.as_ref().map(|it| &**it)
}
pub fn segments(&self) -> PathSegments<'_> {
PathSegments {
segments: self.mod_path.segments.as_slice(),
@ -154,6 +158,7 @@ impl Path {
return None;
}
let res = Path {
type_anchor: self.type_anchor.clone(),
mod_path: ModPath {
kind: self.mod_path.kind.clone(),
segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
@ -226,6 +231,7 @@ impl GenericArgs {
impl From<Name> for Path {
fn from(name: Name) -> Path {
Path {
type_anchor: None,
mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
generic_args: vec![None],
}

View file

@ -22,6 +22,7 @@ pub(super) use lower_use::lower_use_tree;
/// It correctly handles `$crate` based path from macro call.
pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
let mut kind = PathKind::Plain;
let mut type_anchor = None;
let mut segments = Vec::new();
let mut generic_args = Vec::new();
loop {
@ -63,7 +64,8 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
match trait_ref {
// <T>::foo
None => {
kind = PathKind::Type(Box::new(self_type));
type_anchor = Some(Box::new(self_type));
kind = PathKind::Plain;
}
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
Some(trait_ref) => {
@ -111,7 +113,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
segments.reverse();
generic_args.reverse();
let mod_path = ModPath { kind, segments };
return Some(Path { mod_path, generic_args });
return Some(Path { type_anchor, mod_path, generic_args });
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
if let Some(q) = path.qualifier() {

View file

@ -3,7 +3,7 @@
use std::iter;
use hir_def::{
path::{Path, PathKind, PathSegment},
path::{Path, PathSegment},
resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
AssocItemId, ContainerId, Lookup,
};
@ -32,7 +32,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
path: &Path,
id: ExprOrPatId,
) -> Option<Ty> {
let (value, self_subst) = if let PathKind::Type(type_ref) = path.kind() {
let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
if path.segments().is_empty() {
// This can't actually happen syntax-wise
return None;

View file

@ -11,7 +11,7 @@ use std::sync::Arc;
use hir_def::{
builtin_type::BuiltinType,
generics::WherePredicate,
path::{GenericArg, Path, PathKind, PathSegment, PathSegments},
path::{GenericArg, Path, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{TypeBound, TypeRef},
AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
@ -101,7 +101,7 @@ impl Ty {
TypeRef::Path(path) => path,
_ => return None,
};
if let PathKind::Type(_) = path.kind() {
if path.type_anchor().is_some() {
return None;
}
if path.segments().len() > 1 {
@ -202,7 +202,7 @@ impl Ty {
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
// Resolve the path (in type namespace)
if let PathKind::Type(type_ref) = path.kind() {
if let Some(type_ref) = path.type_anchor() {
let ty = Ty::from_hir(db, resolver, &type_ref);
return Ty::from_type_relative_path(db, resolver, ty, path.segments());
}