]> git.lizzy.rs Git - rust.git/commitdiff
Forbid <T>::foo syntax in mod paths
authorAleksey Kladov <aleksey.kladov@gmail.com>
Wed, 18 Dec 2019 16:41:33 +0000 (17:41 +0100)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Wed, 18 Dec 2019 16:41:33 +0000 (17:41 +0100)
crates/ra_assists/src/assists/add_import.rs
crates/ra_hir_def/src/body.rs
crates/ra_hir_def/src/nameres/path_resolution.rs
crates/ra_hir_def/src/path.rs
crates/ra_hir_def/src/path/lower.rs
crates/ra_hir_ty/src/infer/path.rs
crates/ra_hir_ty/src/lower.rs

index ceffee9b87605f1c78d72218786acbeb4ea1f6d5..b8752cbad52aea70267acf22dd0e79a7f257aec9 100644 (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)
index 7787cb87ffe17f159a3f9ed01919b647fc23563c..d4cab05614096cab4fa3d456ace3c1573628dc7e 100644 (file)
@@ -15,7 +15,7 @@
     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 @@ fn enter_expand(
             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 @@ fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
         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()
     }
index 1dbc4f3715ec9786864cd47dda56708b850e5217..2dd779b66e667bb65f3d68fc0016ad16f87682f1 100644 (file)
@@ -145,11 +145,6 @@ pub(super) fn resolve_path_fp_with_macro(
                     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 {
index e38d924faa9260878a5fa67a5f7bbd05558905f3..1e2da6b4812aff5464c3e59c2cbaef4677bb0e49 100644 (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 @@ pub fn as_ident(&self) -> Option<&Name> {
 
 #[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 @@ pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<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 @@ pub fn kind(&self) -> &PathKind {
         &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 @@ pub fn qualifier(&self) -> Option<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 @@ pub(crate) fn empty() -> 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],
         }
index c71b52d8988eb047488b4d1f11bb847bd8ef7b4e..62aafd508e14651d3bde1cd0e2d8fad9b9a36e4d 100644 (file)
@@ -22,6 +22,7 @@
 /// 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() {
index 3bae0ca6c291738f60e3a05729814fd2ceb51736..402a89386ba60ce9a5f119a6638dff3f972205f2 100644 (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 @@ fn resolve_value_path(
         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;
index a4ddfc8efb6572550983da55307a2df7421ba864..2b84309d7aacf2f9936d1afb90b112004a6896b4 100644 (file)
@@ -11,7 +11,7 @@
 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 @@ fn from_hir_only_param(
             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 @@ pub(crate) fn from_partly_resolved_hir_path(
 
     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());
         }