mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Forbid <T>::foo syntax in mod paths
This commit is contained in:
parent
88c6109897
commit
04715cbe1c
7 changed files with 27 additions and 20 deletions
|
@ -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)
|
||||
|
|
|
@ -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(¯o_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()
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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],
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue