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());
|
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()));
|
ps.extend(path.segments().iter().map(|it| it.name.to_string().into()));
|
||||||
Some(ps)
|
Some(ps)
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
expr::{Expr, ExprId, Pat, PatId},
|
expr::{Expr, ExprId, Pat, PatId},
|
||||||
nameres::{BuiltinShadowMode, CrateDefMap},
|
nameres::{BuiltinShadowMode, CrateDefMap},
|
||||||
path::Path,
|
path::{ModPath, Path},
|
||||||
src::HasSource,
|
src::HasSource,
|
||||||
DefWithBodyId, HasModule, Lookup, ModuleId,
|
DefWithBodyId, HasModule, Lookup, ModuleId,
|
||||||
};
|
};
|
||||||
|
@ -44,7 +44,7 @@ impl Expander {
|
||||||
db.ast_id_map(self.current_file_id).ast_id(¯o_call),
|
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) {
|
if let Some(def) = self.resolve_path_as_macro(db, &path) {
|
||||||
let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id));
|
let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id));
|
||||||
let file_id = call_id.as_file();
|
let file_id = call_id.as_file();
|
||||||
|
@ -81,9 +81,13 @@ impl Expander {
|
||||||
Path::from_src(path, &self.hygiene)
|
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
|
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
|
.0
|
||||||
.take_macros()
|
.take_macros()
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,11 +145,6 @@ impl CrateDefMap {
|
||||||
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
|
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 {
|
for (i, segment) in segments {
|
||||||
|
|
|
@ -26,8 +26,6 @@ pub enum PathKind {
|
||||||
Crate,
|
Crate,
|
||||||
/// Absolute path (::foo)
|
/// Absolute path (::foo)
|
||||||
Abs,
|
Abs,
|
||||||
/// Type based path like `<T>::foo`
|
|
||||||
Type(Box<TypeRef>),
|
|
||||||
/// `$crate` from macro expansion
|
/// `$crate` from macro expansion
|
||||||
DollarCrate(CrateId),
|
DollarCrate(CrateId),
|
||||||
}
|
}
|
||||||
|
@ -84,6 +82,8 @@ impl ModPath {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Path {
|
pub struct Path {
|
||||||
|
/// Type based path like `<T>::foo`
|
||||||
|
type_anchor: Option<Box<TypeRef>>,
|
||||||
mod_path: ModPath,
|
mod_path: ModPath,
|
||||||
/// Invariant: the same len as self.path.segments
|
/// Invariant: the same len as self.path.segments
|
||||||
generic_args: Vec<Option<Arc<GenericArgs>>>,
|
generic_args: Vec<Option<Arc<GenericArgs>>>,
|
||||||
|
@ -126,7 +126,7 @@ impl Path {
|
||||||
|
|
||||||
/// Converts an `ast::NameRef` into a single-identifier `Path`.
|
/// Converts an `ast::NameRef` into a single-identifier `Path`.
|
||||||
pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> 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`
|
/// `true` if this path is just a standalone `self`
|
||||||
|
@ -138,6 +138,10 @@ impl Path {
|
||||||
&self.mod_path.kind
|
&self.mod_path.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_anchor(&self) -> Option<&TypeRef> {
|
||||||
|
self.type_anchor.as_ref().map(|it| &**it)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn segments(&self) -> PathSegments<'_> {
|
pub fn segments(&self) -> PathSegments<'_> {
|
||||||
PathSegments {
|
PathSegments {
|
||||||
segments: self.mod_path.segments.as_slice(),
|
segments: self.mod_path.segments.as_slice(),
|
||||||
|
@ -154,6 +158,7 @@ impl Path {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let res = Path {
|
let res = Path {
|
||||||
|
type_anchor: self.type_anchor.clone(),
|
||||||
mod_path: ModPath {
|
mod_path: ModPath {
|
||||||
kind: self.mod_path.kind.clone(),
|
kind: self.mod_path.kind.clone(),
|
||||||
segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
|
segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
|
||||||
|
@ -226,6 +231,7 @@ impl GenericArgs {
|
||||||
impl From<Name> for Path {
|
impl From<Name> for Path {
|
||||||
fn from(name: Name) -> Path {
|
fn from(name: Name) -> Path {
|
||||||
Path {
|
Path {
|
||||||
|
type_anchor: None,
|
||||||
mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
|
mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
|
||||||
generic_args: vec![None],
|
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.
|
/// It correctly handles `$crate` based path from macro call.
|
||||||
pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
|
pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
|
||||||
let mut kind = PathKind::Plain;
|
let mut kind = PathKind::Plain;
|
||||||
|
let mut type_anchor = None;
|
||||||
let mut segments = Vec::new();
|
let mut segments = Vec::new();
|
||||||
let mut generic_args = Vec::new();
|
let mut generic_args = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
|
@ -63,7 +64,8 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
|
||||||
match trait_ref {
|
match trait_ref {
|
||||||
// <T>::foo
|
// <T>::foo
|
||||||
None => {
|
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
|
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
|
||||||
Some(trait_ref) => {
|
Some(trait_ref) => {
|
||||||
|
@ -111,7 +113,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
|
||||||
segments.reverse();
|
segments.reverse();
|
||||||
generic_args.reverse();
|
generic_args.reverse();
|
||||||
let mod_path = ModPath { kind, segments };
|
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> {
|
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
|
||||||
if let Some(q) = path.qualifier() {
|
if let Some(q) = path.qualifier() {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
path::{Path, PathKind, PathSegment},
|
path::{Path, PathSegment},
|
||||||
resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||||
AssocItemId, ContainerId, Lookup,
|
AssocItemId, ContainerId, Lookup,
|
||||||
};
|
};
|
||||||
|
@ -32,7 +32,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
path: &Path,
|
path: &Path,
|
||||||
id: ExprOrPatId,
|
id: ExprOrPatId,
|
||||||
) -> Option<Ty> {
|
) -> 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() {
|
if path.segments().is_empty() {
|
||||||
// This can't actually happen syntax-wise
|
// This can't actually happen syntax-wise
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::sync::Arc;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
builtin_type::BuiltinType,
|
builtin_type::BuiltinType,
|
||||||
generics::WherePredicate,
|
generics::WherePredicate,
|
||||||
path::{GenericArg, Path, PathKind, PathSegment, PathSegments},
|
path::{GenericArg, Path, PathSegment, PathSegments},
|
||||||
resolver::{HasResolver, Resolver, TypeNs},
|
resolver::{HasResolver, Resolver, TypeNs},
|
||||||
type_ref::{TypeBound, TypeRef},
|
type_ref::{TypeBound, TypeRef},
|
||||||
AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
|
AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
|
||||||
|
@ -101,7 +101,7 @@ impl Ty {
|
||||||
TypeRef::Path(path) => path,
|
TypeRef::Path(path) => path,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
if let PathKind::Type(_) = path.kind() {
|
if path.type_anchor().is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if path.segments().len() > 1 {
|
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 {
|
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
|
||||||
// Resolve the path (in type namespace)
|
// 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);
|
let ty = Ty::from_hir(db, resolver, &type_ref);
|
||||||
return Ty::from_type_relative_path(db, resolver, ty, path.segments());
|
return Ty::from_type_relative_path(db, resolver, ty, path.segments());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue