]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/path/lower.rs
Move incorrect case diagnostic things into their module
[rust.git] / crates / hir_def / src / path / lower.rs
index 28f6244da199634dcfc60ccf01cc6649c9bfe260..3abc48d95dfcf03fe54a3074784ec282759479dd 100644 (file)
@@ -3,14 +3,10 @@
 mod lower_use;
 
 use crate::intern::Interned;
-use std::sync::Arc;
 
 use either::Either;
-use hir_expand::{
-    hygiene::Hygiene,
-    name::{name, AsName},
-};
-use syntax::ast::{self, AstNode, TypeBoundsOwner};
+use hir_expand::name::{name, AsName};
+use syntax::ast::{self, AstNode, HasTypeBounds};
 
 use super::AssociatedTypeBinding;
 use crate::{
     type_ref::{LifetimeRef, TypeBound, TypeRef},
 };
 
-pub(super) use lower_use::lower_use_tree;
+pub(super) use lower_use::convert_path;
 
 /// Converts an `ast::Path` to `Path`. Works with use trees.
 /// 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, ctx: &LowerCtx) -> Option<Path> {
     let mut kind = PathKind::Plain;
     let mut type_anchor = None;
     let mut segments = Vec::new();
     let mut generic_args = Vec::new();
-    let ctx = LowerCtx::with_hygiene(hygiene);
+    let hygiene = ctx.hygiene();
     loop {
         let segment = path.segment()?;
 
@@ -39,19 +35,19 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
         match segment.kind()? {
             ast::PathSegmentKind::Name(name_ref) => {
                 // FIXME: this should just return name
-                match hygiene.name_ref_to_name(name_ref) {
+                match hygiene.name_ref_to_name(ctx.db.upcast(), name_ref) {
                     Either::Left(name) => {
                         let args = segment
                             .generic_arg_list()
-                            .and_then(|it| lower_generic_args(&ctx, it))
+                            .and_then(|it| lower_generic_args(ctx, it))
                             .or_else(|| {
                                 lower_generic_args_from_fn_path(
-                                    &ctx,
+                                    ctx,
                                     segment.param_list(),
                                     segment.ret_type(),
                                 )
                             })
-                            .map(Arc::new);
+                            .map(Interned::new);
                         segments.push(name);
                         generic_args.push(args)
                     }
@@ -64,39 +60,34 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
             ast::PathSegmentKind::Type { type_ref, trait_ref } => {
                 assert!(path.qualifier().is_none()); // this can only occur at the first segment
 
-                let self_type = TypeRef::from_ast(&ctx, type_ref?);
+                let self_type = TypeRef::from_ast(ctx, type_ref?);
 
                 match trait_ref {
                     // <T>::foo
                     None => {
-                        type_anchor = Some(Box::new(self_type));
+                        type_anchor = Some(Interned::new(self_type));
                         kind = PathKind::Plain;
                     }
                     // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
                     Some(trait_ref) => {
-                        let path = Path::from_src(trait_ref.path()?, hygiene)?;
-                        let mod_path = (*path.mod_path).clone();
-                        let num_segments = path.mod_path.segments.len();
+                        let Path { mod_path, generic_args: path_generic_args, .. } =
+                            Path::from_src(trait_ref.path()?, ctx)?;
+                        let num_segments = mod_path.segments.len();
                         kind = mod_path.kind;
 
-                        let mut prefix_segments = mod_path.segments;
-                        prefix_segments.reverse();
-                        segments.extend(prefix_segments);
-
-                        let mut prefix_args = path.generic_args;
-                        prefix_args.reverse();
-                        generic_args.extend(prefix_args);
+                        segments.extend(mod_path.segments.iter().cloned().rev());
+                        generic_args.extend(Vec::from(path_generic_args).into_iter().rev());
 
                         // Insert the type reference (T in the above example) as Self parameter for the trait
                         let last_segment =
                             generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?;
-                        if last_segment.is_none() {
-                            *last_segment = Some(Arc::new(GenericArgs::empty()));
+                        let mut args_inner = match last_segment {
+                            Some(it) => it.as_ref().clone(),
+                            None => GenericArgs::empty(),
                         };
-                        let args = last_segment.as_mut().unwrap();
-                        let mut args_inner = Arc::make_mut(args);
                         args_inner.has_self_type = true;
                         args_inner.args.insert(0, GenericArg::Type(self_type));
+                        *last_segment = Some(Interned::new(args_inner));
                     }
                 }
             }
@@ -105,7 +96,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
                 break;
             }
             ast::PathSegmentKind::SelfKw => {
-                // don't break out if `self` is the last segment of a path, this mean we got an
+                // don't break out if `self` is the last segment of a path, this mean we got a
                 // use tree like `foo::{self}` which we want to resolve as `foo`
                 if !segments.is_empty() {
                     kind = PathKind::Super(0);
@@ -136,14 +127,14 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
     // We follow what it did anyway :)
     if segments.len() == 1 && kind == PathKind::Plain {
         if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
-            if let Some(crate_id) = hygiene.local_inner_macros(path) {
+            if let Some(crate_id) = hygiene.local_inner_macros(ctx.db.upcast(), path) {
                 kind = PathKind::DollarCrate(crate_id);
             }
         }
     }
 
     let mod_path = Interned::new(ModPath::from_segments(kind, segments));
-    return Some(Path { type_anchor, mod_path, generic_args });
+    return Some(Path { type_anchor, mod_path, generic_args: generic_args.into() });
 
     fn qualifier(path: &ast::Path) -> Option<ast::Path> {
         if let Some(q) = path.qualifier() {
@@ -174,7 +165,9 @@ pub(super) fn lower_generic_args(
                     let name = name_ref.as_name();
                     let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
                     let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
-                        l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
+                        l.bounds()
+                            .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
+                            .collect()
                     } else {
                         Vec::new()
                     };
@@ -195,7 +188,7 @@ pub(super) fn lower_generic_args(
     if args.is_empty() && bindings.is_empty() {
         return None;
     }
-    Some(GenericArgs { args, has_self_type: false, bindings })
+    Some(GenericArgs { args, has_self_type: false, bindings, desugared_from_fn: false })
 }
 
 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
@@ -207,26 +200,29 @@ fn lower_generic_args_from_fn_path(
 ) -> Option<GenericArgs> {
     let mut args = Vec::new();
     let mut bindings = Vec::new();
-    if let Some(params) = params {
-        let mut param_types = Vec::new();
-        for param in params.params() {
-            let type_ref = TypeRef::from_ast_opt(&ctx, param.ty());
-            param_types.push(type_ref);
-        }
-        let arg = GenericArg::Type(TypeRef::Tuple(param_types));
-        args.push(arg);
+    let params = params?;
+    let mut param_types = Vec::new();
+    for param in params.params() {
+        let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
+        param_types.push(type_ref);
     }
+    let arg = GenericArg::Type(TypeRef::Tuple(param_types));
+    args.push(arg);
     if let Some(ret_type) = ret_type {
-        let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty());
+        let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
         bindings.push(AssociatedTypeBinding {
             name: name![Output],
             type_ref: Some(type_ref),
             bounds: Vec::new(),
         });
-    }
-    if args.is_empty() && bindings.is_empty() {
-        None
     } else {
-        Some(GenericArgs { args, has_self_type: false, bindings })
+        // -> ()
+        let type_ref = TypeRef::Tuple(Vec::new());
+        bindings.push(AssociatedTypeBinding {
+            name: name![Output],
+            type_ref: Some(type_ref),
+            bounds: Vec::new(),
+        });
     }
+    Some(GenericArgs { args, has_self_type: false, bindings, desugared_from_fn: true })
 }