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()); 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)

View file

@ -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(&macro_call), 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) { 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()
} }

View file

@ -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 {

View file

@ -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],
} }

View file

@ -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() {

View file

@ -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;

View file

@ -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());
} }