]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir/src/semantics.rs
Add ConstParams to the HIR
[rust.git] / crates / hir / src / semantics.rs
index 4315ad48b9c4b31b7736b22fdc11bde73c68485e..cd689c86935e24ebad1be98f3685126b96d99bf9 100644 (file)
 use hir_ty::associated_type_shorthand_candidates;
 use itertools::Itertools;
 use rustc_hash::{FxHashMap, FxHashSet};
-use syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode, SyntaxToken, TextSize};
+use syntax::{
+    algo::find_node_at_offset,
+    ast::{self, GenericParamsOwner, LoopBodyOwner},
+    match_ast, AstNode, SyntaxNode, SyntaxToken, TextSize,
+};
 
 use crate::{
     code_model::Access,
@@ -21,8 +25,9 @@
     diagnostics::Diagnostic,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
     source_analyzer::{resolve_hir_path, SourceAnalyzer},
-    AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
-    Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
+    AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label,
+    LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type,
+    TypeAlias, TypeParam, VariantDef,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -33,7 +38,8 @@ pub enum PathResolution {
     Local(Local),
     /// A generic parameter
     TypeParam(TypeParam),
-    SelfType(ImplDef),
+    ConstParam(ConstParam),
+    SelfType(Impl),
     Macro(MacroDef),
     AssocItem(AssocItem),
 }
@@ -46,7 +52,7 @@ fn in_type_ns(&self) -> Option<TypeNs> {
                 Some(TypeNs::BuiltinType(*builtin))
             }
             PathResolution::Def(ModuleDef::Const(_))
-            | PathResolution::Def(ModuleDef::EnumVariant(_))
+            | PathResolution::Def(ModuleDef::Variant(_))
             | PathResolution::Def(ModuleDef::Function(_))
             | PathResolution::Def(ModuleDef::Module(_))
             | PathResolution::Def(ModuleDef::Static(_))
@@ -54,7 +60,9 @@ fn in_type_ns(&self) -> Option<TypeNs> {
             PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
                 Some(TypeNs::TypeAliasId((*alias).into()))
             }
-            PathResolution::Local(_) | PathResolution::Macro(_) => None,
+            PathResolution::Local(_) | PathResolution::Macro(_) | PathResolution::ConstParam(_) => {
+                None
+            }
             PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
             PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
             PathResolution::AssocItem(AssocItem::Const(_))
@@ -173,6 +181,14 @@ pub fn find_node_at_offset_with_descend<N: AstNode>(
         self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
     }
 
+    pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
+        self.imp.resolve_lifetime_param(lifetime)
+    }
+
+    pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
+        self.imp.resolve_label(lifetime)
+    }
+
     pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
         self.imp.type_of_expr(expr)
     }
@@ -294,9 +310,8 @@ fn parse(&self, file_id: FileId) -> ast::SourceFile {
     }
 
     fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
-        let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
-        let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
-        let file_id = sa.expand(self.db, macro_call)?;
+        let sa = self.analyze(macro_call.syntax());
+        let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?;
         let node = self.db.parse_or_expand(file_id)?;
         self.cache(node.clone(), file_id);
         Some(node)
@@ -308,9 +323,8 @@ fn speculative_expand(
         hypothetical_args: &ast::TokenTree,
         token_to_map: SyntaxToken,
     ) -> Option<(SyntaxNode, SyntaxToken)> {
-        let macro_call =
-            self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
-        let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
+        let sa = self.analyze(actual_macro_call.syntax());
+        let macro_call = InFile::new(sa.file_id, actual_macro_call);
         let krate = sa.resolver.krate()?;
         let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
             sa.resolver.resolve_path_as_macro(self.db.upcast(), &path)
@@ -326,10 +340,9 @@ fn speculative_expand(
     fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
         let _p = profile::span("descend_into_macros");
         let parent = token.parent();
-        let parent = self.find_file(parent);
-        let sa = self.analyze2(parent.as_ref(), None);
+        let sa = self.analyze(&parent);
 
-        let token = successors(Some(parent.with_value(token)), |token| {
+        let token = successors(Some(InFile::new(sa.file_id, token)), |token| {
             self.db.check_canceled();
             let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
             let tt = macro_call.token_tree()?;
@@ -395,16 +408,62 @@ fn ancestors_at_offset_with_macros(
             .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
     }
 
+    fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
+        let text = lifetime.text();
+        let lifetime_param = lifetime.syntax().ancestors().find_map(|syn| {
+            let gpl = match_ast! {
+                match syn {
+                    ast::Fn(it) => it.generic_param_list()?,
+                    ast::TypeAlias(it) => it.generic_param_list()?,
+                    ast::Struct(it) => it.generic_param_list()?,
+                    ast::Enum(it) => it.generic_param_list()?,
+                    ast::Union(it) => it.generic_param_list()?,
+                    ast::Trait(it) => it.generic_param_list()?,
+                    ast::Impl(it) => it.generic_param_list()?,
+                    ast::WherePred(it) => it.generic_param_list()?,
+                    ast::ForType(it) => it.generic_param_list()?,
+                    _ => return None,
+                }
+            };
+            gpl.lifetime_params()
+                .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()) == Some(text))
+        })?;
+        let src = self.find_file(lifetime_param.syntax().clone()).with_value(lifetime_param);
+        ToDef::to_def(self, src)
+    }
+
+    fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
+        let text = lifetime.text();
+        let label = lifetime.syntax().ancestors().find_map(|syn| {
+            let label = match_ast! {
+                match syn {
+                    ast::ForExpr(it) => it.label(),
+                    ast::WhileExpr(it) => it.label(),
+                    ast::LoopExpr(it) => it.label(),
+                    ast::EffectExpr(it) => it.label(),
+                    _ => None,
+                }
+            };
+            label.filter(|l| {
+                l.lifetime()
+                    .and_then(|lt| lt.lifetime_ident_token())
+                    .map_or(false, |lt| lt.text() == text)
+            })
+        })?;
+        let src = self.find_file(label.syntax().clone()).with_value(label);
+        ToDef::to_def(self, src)
+    }
+
     fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
-        self.analyze(expr.syntax()).type_of_expr(self.db, &expr)
+        self.analyze(expr.syntax()).type_of_expr(self.db, expr)
     }
 
     fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
-        self.analyze(pat.syntax()).type_of_pat(self.db, &pat)
+        self.analyze(pat.syntax()).type_of_pat(self.db, pat)
     }
 
     fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
-        self.analyze(param.syntax()).type_of_self(self.db, &param)
+        self.analyze(param.syntax()).type_of_self(self.db, param)
     }
 
     fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
@@ -486,15 +545,13 @@ fn to_module_def(&self, file: FileId) -> Option<Module> {
     }
 
     fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
-        let node = self.find_file(node.clone());
-        let resolver = self.analyze2(node.as_ref(), None).resolver;
-        SemanticsScope { db: self.db, file_id: node.file_id, resolver }
+        let sa = self.analyze(node);
+        SemanticsScope { db: self.db, file_id: sa.file_id, resolver: sa.resolver }
     }
 
     fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
-        let node = self.find_file(node.clone());
-        let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver;
-        SemanticsScope { db: self.db, file_id: node.file_id, resolver }
+        let sa = self.analyze_with_offset(node, offset);
+        SemanticsScope { db: self.db, file_id: sa.file_id, resolver: sa.resolver }
     }
 
     fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
@@ -504,21 +561,24 @@ fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
     }
 
     fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer {
-        let src = self.find_file(node.clone());
-        self.analyze2(src.as_ref(), None)
+        self.analyze_impl(node, None)
     }
+    fn analyze_with_offset(&self, node: &SyntaxNode, offset: TextSize) -> SourceAnalyzer {
+        self.analyze_impl(node, Some(offset))
+    }
+    fn analyze_impl(&self, node: &SyntaxNode, offset: Option<TextSize>) -> SourceAnalyzer {
+        let _p = profile::span("Semantics::analyze_impl");
+        let node = self.find_file(node.clone());
+        let node = node.as_ref();
 
-    fn analyze2(&self, src: InFile<&SyntaxNode>, offset: Option<TextSize>) -> SourceAnalyzer {
-        let _p = profile::span("Semantics::analyze2");
-
-        let container = match self.with_ctx(|ctx| ctx.find_container(src)) {
+        let container = match self.with_ctx(|ctx| ctx.find_container(node)) {
             Some(it) => it,
-            None => return SourceAnalyzer::new_for_resolver(Resolver::default(), src),
+            None => return SourceAnalyzer::new_for_resolver(Resolver::default(), node),
         };
 
         let resolver = match container {
             ChildContainer::DefWithBodyId(def) => {
-                return SourceAnalyzer::new_for_body(self.db, def, src, offset)
+                return SourceAnalyzer::new_for_body(self.db, def, node, offset)
             }
             ChildContainer::TraitId(it) => it.resolver(self.db.upcast()),
             ChildContainer::ImplId(it) => it.resolver(self.db.upcast()),
@@ -528,7 +588,7 @@ fn analyze2(&self, src: InFile<&SyntaxNode>, offset: Option<TextSize>) -> Source
             ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()),
             ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()),
         };
-        SourceAnalyzer::new_for_resolver(resolver, src)
+        SourceAnalyzer::new_for_resolver(resolver, node)
     }
 
     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
@@ -677,17 +737,20 @@ fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def> {
     (crate::Enum, ast::Enum, enum_to_def),
     (crate::Union, ast::Union, union_to_def),
     (crate::Trait, ast::Trait, trait_to_def),
-    (crate::ImplDef, ast::Impl, impl_to_def),
+    (crate::Impl, ast::Impl, impl_to_def),
     (crate::TypeAlias, ast::TypeAlias, type_alias_to_def),
     (crate::Const, ast::Const, const_to_def),
     (crate::Static, ast::Static, static_to_def),
     (crate::Function, ast::Fn, fn_to_def),
     (crate::Field, ast::RecordField, record_field_to_def),
     (crate::Field, ast::TupleField, tuple_field_to_def),
-    (crate::EnumVariant, ast::Variant, enum_variant_to_def),
+    (crate::Variant, ast::Variant, enum_variant_to_def),
     (crate::TypeParam, ast::TypeParam, type_param_to_def),
-    (crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros
+    (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
+    (crate::ConstParam, ast::ConstParam, const_param_to_def),
+    (crate::MacroDef, ast::MacroRules, macro_rules_to_def),
     (crate::Local, ast::IdentPat, bind_pat_to_def),
+    (crate::Label, ast::Label, label_to_def),
 ];
 
 fn find_root(node: &SyntaxNode) -> SyntaxNode {