]> git.lizzy.rs Git - rust.git/commitdiff
Resolve the Self type
authorFlorian Diebold <flodiebold@gmail.com>
Sat, 29 Dec 2018 22:20:12 +0000 (23:20 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Fri, 4 Jan 2019 18:13:50 +0000 (19:13 +0100)
crates/ra_hir/src/name.rs
crates/ra_hir/src/ty.rs
crates/ra_hir/src/ty/tests/data/0007_self.txt

index 51e8b3da86f4a58e31af945c46b964b95f360d45..017caf442e29c56b082c6e6280741bd79689ec7d 100644 (file)
@@ -51,6 +51,7 @@ pub(crate) fn as_known_name(&self) -> Option<KnownName> {
             "u128" => KnownName::U128,
             "f32" => KnownName::F32,
             "f64" => KnownName::F64,
+            "Self" => KnownName::Self_,
             _ => return None,
         };
         Some(name)
@@ -84,7 +85,7 @@ fn as_name(&self) -> Name {
 // const ISIZE: Name = Name::new("isize")
 // ```
 // but const-fn is not that powerful yet.
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq)]
 pub(crate) enum KnownName {
     Isize,
     I8,
@@ -102,4 +103,6 @@ pub(crate) enum KnownName {
 
     F32,
     F64,
+
+    Self_,
 }
index 5ea62a14cfa398c97910baef3801dc3ccb23fcea..d11f80cffb844401a7830d90a93a620f2fbb71a8 100644 (file)
 };
 
 use crate::{
-    Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName,
+    Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock,
     db::HirDatabase,
     type_ref::{TypeRef, Mutability},
+    name::KnownName,
 };
 
 /// The ID of a type variable.
@@ -235,6 +236,7 @@ impl Ty {
     pub(crate) fn from_hir(
         db: &impl HirDatabase,
         module: &Module,
+        impl_block: Option<&ImplBlock>,
         type_ref: &TypeRef,
     ) -> Cancelable<Self> {
         Ok(match type_ref {
@@ -242,29 +244,29 @@ pub(crate) fn from_hir(
             TypeRef::Tuple(inner) => {
                 let inner_tys = inner
                     .iter()
-                    .map(|tr| Ty::from_hir(db, module, tr))
+                    .map(|tr| Ty::from_hir(db, module, impl_block, tr))
                     .collect::<Cancelable<Vec<_>>>()?;
                 Ty::Tuple(inner_tys.into())
             }
-            TypeRef::Path(path) => Ty::from_hir_path(db, module, path)?,
+            TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, path)?,
             TypeRef::RawPtr(inner, mutability) => {
-                let inner_ty = Ty::from_hir(db, module, inner)?;
+                let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
                 Ty::RawPtr(Arc::new(inner_ty), *mutability)
             }
             TypeRef::Array(_inner) => Ty::Unknown, // TODO
             TypeRef::Slice(inner) => {
-                let inner_ty = Ty::from_hir(db, module, inner)?;
+                let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
                 Ty::Slice(Arc::new(inner_ty))
             }
             TypeRef::Reference(inner, mutability) => {
-                let inner_ty = Ty::from_hir(db, module, inner)?;
+                let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
                 Ty::Ref(Arc::new(inner_ty), *mutability)
             }
             TypeRef::Placeholder => Ty::Unknown,
             TypeRef::Fn(params) => {
                 let mut inner_tys = params
                     .iter()
-                    .map(|tr| Ty::from_hir(db, module, tr))
+                    .map(|tr| Ty::from_hir(db, module, impl_block, tr))
                     .collect::<Cancelable<Vec<_>>>()?;
                 let return_ty = inner_tys
                     .pop()
@@ -279,9 +281,21 @@ pub(crate) fn from_hir(
         })
     }
 
+    pub(crate) fn from_hir_opt(
+        db: &impl HirDatabase,
+        module: &Module,
+        impl_block: Option<&ImplBlock>,
+        type_ref: Option<&TypeRef>,
+    ) -> Cancelable<Self> {
+        type_ref
+            .map(|t| Ty::from_hir(db, module, impl_block, t))
+            .unwrap_or(Ok(Ty::Unknown))
+    }
+
     pub(crate) fn from_hir_path(
         db: &impl HirDatabase,
         module: &Module,
+        impl_block: Option<&ImplBlock>,
         path: &Path,
     ) -> Cancelable<Self> {
         if let Some(name) = path.as_ident() {
@@ -291,6 +305,8 @@ pub(crate) fn from_hir_path(
                 return Ok(Ty::Uint(uint_ty));
             } else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
                 return Ok(Ty::Float(float_ty));
+            } else if name.as_known_name() == Some(KnownName::Self_) {
+                return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target()));
             }
         }
 
@@ -308,18 +324,20 @@ pub(crate) fn from_hir_path(
     pub(crate) fn from_ast_opt(
         db: &impl HirDatabase,
         module: &Module,
+        impl_block: Option<&ImplBlock>,
         node: Option<ast::TypeRef>,
     ) -> Cancelable<Self> {
-        node.map(|n| Ty::from_ast(db, module, n))
+        node.map(|n| Ty::from_ast(db, module, impl_block, n))
             .unwrap_or(Ok(Ty::Unknown))
     }
 
     pub(crate) fn from_ast(
         db: &impl HirDatabase,
         module: &Module,
+        impl_block: Option<&ImplBlock>,
         node: ast::TypeRef,
     ) -> Cancelable<Self> {
-        Ty::from_hir(db, module, &TypeRef::from_ast(node))
+        Ty::from_hir(db, module, impl_block, &TypeRef::from_ast(node))
     }
 
     pub fn unit() -> Self {
@@ -402,18 +420,19 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
     let syntax = f.syntax(db);
     let module = f.module(db)?;
+    let impl_block = f.impl_block(db)?;
     let node = syntax.borrowed();
     // TODO we ignore type parameters for now
     let input = node
         .param_list()
         .map(|pl| {
             pl.params()
-                .map(|p| Ty::from_ast_opt(db, &module, p.type_ref()))
+                .map(|p| Ty::from_ast_opt(db, &module, impl_block.as_ref(), p.type_ref()))
                 .collect()
         })
         .unwrap_or_else(|| Ok(Vec::new()))?;
     let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) {
-        Ty::from_ast(db, &module, type_ref)?
+        Ty::from_ast(db, &module, impl_block.as_ref(), type_ref)?
     } else {
         Ty::unit()
     };
@@ -467,12 +486,13 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name)
         ),
     };
     let module = def_id.module(db)?;
+    let impl_block = def_id.impl_block(db)?;
     let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) {
         tr
     } else {
         return Ok(Ty::Unknown);
     };
-    Ty::from_hir(db, &module, &type_ref)
+    Ty::from_hir(db, &module, impl_block.as_ref(), &type_ref)
 }
 
 /// The result of type inference: A mapping from expressions and patterns to types.
@@ -499,12 +519,18 @@ struct InferenceContext<'a, D: HirDatabase> {
     /// The self param for the current method, if it exists.
     self_param: Option<LocalSyntaxPtr>,
     module: Module,
+    impl_block: Option<ImplBlock>,
     var_unification_table: InPlaceUnificationTable<TypeVarId>,
     type_of: FxHashMap<LocalSyntaxPtr, Ty>,
 }
 
 impl<'a, D: HirDatabase> InferenceContext<'a, D> {
-    fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self {
+    fn new(
+        db: &'a D,
+        scopes: Arc<FnScopes>,
+        module: Module,
+        impl_block: Option<ImplBlock>,
+    ) -> Self {
         InferenceContext {
             type_of: FxHashMap::default(),
             var_unification_table: InPlaceUnificationTable::new(),
@@ -512,6 +538,7 @@ fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self {
             db,
             scopes,
             module,
+            impl_block,
         }
     }
 
@@ -835,7 +862,12 @@ fn infer_expr(&mut self, expr: ast::Expr, expected: &Expectation) -> Cancelable<
             }
             ast::Expr::CastExpr(e) => {
                 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
-                let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?;
+                let cast_ty = Ty::from_ast_opt(
+                    self.db,
+                    &self.module,
+                    self.impl_block.as_ref(),
+                    e.type_ref(),
+                )?;
                 let cast_ty = self.insert_type_vars(cast_ty);
                 // TODO do the coercion...
                 cast_ty
@@ -889,7 +921,12 @@ fn infer_block(&mut self, node: ast::Block, expected: &Expectation) -> Cancelabl
         for stmt in node.statements() {
             match stmt {
                 ast::Stmt::LetStmt(stmt) => {
-                    let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?;
+                    let decl_ty = Ty::from_ast_opt(
+                        self.db,
+                        &self.module,
+                        self.impl_block.as_ref(),
+                        stmt.type_ref(),
+                    )?;
                     let decl_ty = self.insert_type_vars(decl_ty);
                     let ty = if let Some(expr) = stmt.initializer() {
                         let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?;
@@ -921,19 +958,26 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe
     let function = Function::new(def_id); // TODO: consts also need inference
     let scopes = function.scopes(db);
     let module = function.module(db)?;
-    let mut ctx = InferenceContext::new(db, scopes, module);
+    let impl_block = function.impl_block(db)?;
+    let mut ctx = InferenceContext::new(db, scopes, module, impl_block);
 
     let syntax = function.syntax(db);
     let node = syntax.borrowed();
 
     if let Some(param_list) = node.param_list() {
         if let Some(self_param) = param_list.self_param() {
-            let self_type = if let Some(impl_block) = function.impl_block(db)? {
+            let self_type = if let Some(impl_block) = &ctx.impl_block {
                 if let Some(type_ref) = self_param.type_ref() {
-                    let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
+                    let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?;
                     ctx.insert_type_vars(ty)
                 } else {
-                    let ty = Ty::from_hir(db, &ctx.module, impl_block.target())?;
+                    // TODO this should be handled by desugaring during HIR conversion
+                    let ty = Ty::from_hir(
+                        db,
+                        &ctx.module,
+                        ctx.impl_block.as_ref(),
+                        impl_block.target(),
+                    )?;
                     let ty = match self_param.flavor() {
                         ast::SelfParamFlavor::Owned => ty,
                         ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared),
@@ -961,7 +1005,7 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe
                 continue;
             };
             let ty = if let Some(type_ref) = param.type_ref() {
-                let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
+                let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?;
                 ctx.insert_type_vars(ty)
             } else {
                 // missing type annotation
@@ -972,7 +1016,7 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe
     }
 
     let ret_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) {
-        let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
+        let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?;
         ctx.insert_type_vars(ty)
     } else {
         Ty::unit()
index 0dd61da559f509dc022cd8c9a025b2b544a8f5d7..db4ba17d07915d25e96b8a521c4f4d89914eba13 100644 (file)
@@ -2,5 +2,5 @@
 [34; 38) 'self': &S
 [40; 61) '{     ...     }': ()
 [88; 109) '{     ...     }': ()
-[98; 102) 'self': &[unknown]
-[75; 79) 'self': &[unknown]
+[98; 102) 'self': &S
+[75; 79) 'self': &S