Skip to content

Commit a5bf10b

Browse files
committed
feat: type alias
1 parent 7147826 commit a5bf10b

33 files changed

+552
-41
lines changed

crates/mun_codegen/src/ir/file_group.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub(crate) fn gen_file_group_ir<'db, 'ink>(
6565
ModuleDef::Function(_) => (), // TODO: Extern types?
6666
ModuleDef::Struct(_) => (),
6767
ModuleDef::BuiltinType(_) => (),
68+
ModuleDef::TypeAlias(_) => (),
6869
}
6970
}
7071

@@ -118,7 +119,7 @@ pub(crate) fn gen_file_group_ir<'db, 'ink>(
118119
ModuleDef::Function(f) => {
119120
type_table_builder.collect_fn(*f);
120121
}
121-
ModuleDef::BuiltinType(_) => (),
122+
ModuleDef::BuiltinType(_) | ModuleDef::TypeAlias(_) => (),
122123
}
123124
}
124125

crates/mun_compiler/src/diagnostics.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,19 @@ mod tests {
7979
"\n\nstruct Foo {\ni: bool\n}\n\nfn main() {\nlet a = Foo { i: false };\nlet b = a.t;\n}"
8080
));
8181
}
82+
83+
#[test]
84+
fn test_free_type_alias_error() {
85+
insta::assert_display_snapshot!(compilation_errors("\n\ntype Foo;"));
86+
}
87+
88+
#[test]
89+
fn test_type_alias_target_undeclared_error() {
90+
insta::assert_display_snapshot!(compilation_errors("\n\ntype Foo = UnknownType;"));
91+
}
92+
93+
#[test]
94+
fn test_cyclic_type_alias_error() {
95+
insta::assert_display_snapshot!(compilation_errors("\n\ntype Foo = Foo;"));
96+
}
8297
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
source: crates/mun_compiler/src/diagnostics.rs
3+
expression: "compilation_errors(\"\\n\\ntype Foo = Foo;\")"
4+
---
5+
error: cyclic type
6+
--> main.mun:3:12
7+
|
8+
3 | type Foo = Foo;
9+
| ^^^ cyclic type
10+
|
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
source: crates/mun_compiler/src/diagnostics.rs
3+
expression: "compilation_errors(\"\\n\\ntype Foo;\")"
4+
---
5+
error: free type alias without type ref
6+
--> main.mun:3:1
7+
|
8+
3 | type Foo;
9+
| ^^^^^^^^^ free type alias without type ref
10+
|
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
source: crates/mun_compiler/src/diagnostics.rs
3+
expression: "compilation_errors(\"\\n\\ntype Foo = UnknownType;\")"
4+
---
5+
error: cannot find type `UnknownType` in this scope
6+
--> main.mun:3:12
7+
|
8+
3 | type Foo = UnknownType;
9+
| ^^^^^^^^^^^ not found in this scope
10+
|

crates/mun_hir/src/adt.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{fmt, sync::Arc};
33
use crate::type_ref::{TypeRefBuilder, TypeRefId, TypeRefMap, TypeRefSourceMap};
44
use crate::{
55
arena::{Arena, RawId},
6-
ids::{AstItemDef, StructId},
6+
ids::{AstItemDef, StructId, TypeAliasId},
77
AsName, DefDatabase, Name,
88
};
99
use mun_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
@@ -121,3 +121,42 @@ impl StructData {
121121
&self.type_ref_map
122122
}
123123
}
124+
125+
#[derive(Debug, PartialEq, Eq)]
126+
pub struct TypeAliasData {
127+
pub name: Name,
128+
pub type_ref_id: TypeRefId,
129+
type_ref_map: TypeRefMap,
130+
type_ref_source_map: TypeRefSourceMap,
131+
}
132+
impl TypeAliasData {
133+
pub(crate) fn type_alias_data_query(
134+
db: &dyn DefDatabase,
135+
id: TypeAliasId,
136+
) -> Arc<TypeAliasData> {
137+
let src = id.source(db);
138+
let name = src
139+
.value
140+
.name()
141+
.map(|n| n.as_name())
142+
.unwrap_or_else(Name::missing);
143+
let mut type_ref_builder = TypeRefBuilder::default();
144+
let type_ref_opt = src.value.type_ref();
145+
let type_ref_id = type_ref_builder.alloc_from_node_opt(type_ref_opt.as_ref());
146+
let (type_ref_map, type_ref_source_map) = type_ref_builder.finish();
147+
Arc::new(TypeAliasData {
148+
name,
149+
type_ref_id,
150+
type_ref_map,
151+
type_ref_source_map,
152+
})
153+
}
154+
155+
pub fn type_ref_source_map(&self) -> &TypeRefSourceMap {
156+
&self.type_ref_source_map
157+
}
158+
159+
pub fn type_ref_map(&self) -> &TypeRefMap {
160+
&self.type_ref_map
161+
}
162+
}

crates/mun_hir/src/code_model.rs

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
pub(crate) mod src;
22

33
use self::src::HasSource;
4-
use crate::adt::{StructData, StructFieldId};
4+
use crate::adt::{StructData, StructFieldId, TypeAliasData};
55
use crate::builtin_type::BuiltinType;
66
use crate::code_model::diagnostics::ModuleDefinitionDiagnostic;
77
use crate::diagnostics::DiagnosticSink;
8-
use crate::expr::validator::ExprValidator;
8+
use crate::expr::validator::{ExprValidator, TypeAliasValidator};
99
use crate::expr::{Body, BodySourceMap};
1010
use crate::ids::AstItemDef;
1111
use crate::ids::LocationCtx;
@@ -15,7 +15,7 @@ use crate::resolve::{Resolution, Resolver};
1515
use crate::ty::{lower::LowerBatchResult, InferenceResult};
1616
use crate::type_ref::{TypeRefBuilder, TypeRefId, TypeRefMap, TypeRefSourceMap};
1717
use crate::{
18-
ids::{FunctionId, StructId},
18+
ids::{FunctionId, StructId, TypeAliasId},
1919
AsName, DefDatabase, FileId, HirDatabase, Name, Ty,
2020
};
2121
use mun_syntax::ast::{ExternOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner};
@@ -52,11 +52,11 @@ impl Module {
5252
diag.add_to(db.upcast(), self, sink);
5353
}
5454
for decl in self.declarations(db) {
55-
#[allow(clippy::single_match)]
5655
match decl {
5756
ModuleDef::Function(f) => f.diagnostics(db, sink),
5857
ModuleDef::Struct(s) => s.diagnostics(db, sink),
59-
_ => (),
58+
ModuleDef::TypeAlias(t) => t.diagnostics(db, sink),
59+
ModuleDef::BuiltinType(_) => (),
6060
}
6161
}
6262
}
@@ -104,6 +104,11 @@ impl ModuleData {
104104
id: StructId::from_ast_id(loc_ctx, ast_id),
105105
}))
106106
}
107+
DefKind::TypeAlias(ast_id) => {
108+
data.definitions.push(ModuleDef::TypeAlias(TypeAlias {
109+
id: TypeAliasId::from_ast_id(loc_ctx, ast_id),
110+
}))
111+
}
107112
}
108113
}
109114
};
@@ -121,6 +126,7 @@ pub enum ModuleDef {
121126
Function(Function),
122127
BuiltinType(BuiltinType),
123128
Struct(Struct),
129+
TypeAlias(TypeAlias),
124130
}
125131

126132
impl From<Function> for ModuleDef {
@@ -328,7 +334,8 @@ impl Function {
328334
}
329335

330336
pub fn ty(self, db: &dyn HirDatabase) -> Ty {
331-
db.type_for_def(self.into(), Namespace::Values)
337+
// TODO: Add detection of cyclick types
338+
db.type_for_def(self.into(), Namespace::Values).0
332339
}
333340

334341
pub fn infer(self, db: &dyn HirDatabase) -> Arc<InferenceResult> {
@@ -418,7 +425,8 @@ impl Struct {
418425
}
419426

420427
pub fn ty(self, db: &dyn HirDatabase) -> Ty {
421-
db.type_for_def(self.into(), Namespace::Types)
428+
// TODO: Add detection of cyclick types
429+
db.type_for_def(self.into(), Namespace::Types).0
422430
}
423431

424432
pub fn lower(self, db: &dyn HirDatabase) -> Arc<LowerBatchResult> {
@@ -442,6 +450,54 @@ impl Struct {
442450
}
443451
}
444452

453+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
454+
pub struct TypeAlias {
455+
pub(crate) id: TypeAliasId,
456+
}
457+
458+
impl TypeAlias {
459+
pub fn module(self, db: &dyn DefDatabase) -> Module {
460+
Module {
461+
file_id: self.id.file_id(db),
462+
}
463+
}
464+
465+
pub fn data(self, db: &dyn DefDatabase) -> Arc<TypeAliasData> {
466+
db.type_alias_data(self.id)
467+
}
468+
469+
pub fn name(self, db: &dyn DefDatabase) -> Name {
470+
self.data(db).name.clone()
471+
}
472+
473+
pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRefId {
474+
self.data(db.upcast()).type_ref_id
475+
}
476+
477+
pub fn lower(self, db: &dyn HirDatabase) -> Arc<LowerBatchResult> {
478+
db.lower_type_alias(self)
479+
}
480+
481+
pub(crate) fn resolver(self, db: &dyn HirDatabase) -> Resolver {
482+
// take the outer scope...
483+
self.module(db.upcast()).resolver(db.upcast())
484+
}
485+
486+
pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
487+
let data = self.data(db.upcast());
488+
let lower = self.lower(db);
489+
lower.add_diagnostics(
490+
db,
491+
self.module(db.upcast()).file_id,
492+
data.type_ref_source_map(),
493+
sink,
494+
);
495+
496+
let validator = TypeAliasValidator::new(self, db);
497+
validator.validate_target_type_existence(sink);
498+
}
499+
}
500+
445501
mod diagnostics {
446502
use super::Module;
447503
use crate::diagnostics::{DiagnosticSink, DuplicateDefinition};
@@ -466,6 +522,9 @@ mod diagnostics {
466522
DefKind::Struct(id) => {
467523
SyntaxNodePtr::new(id.with_file_id(owner.file_id).to_node(db).syntax())
468524
}
525+
DefKind::TypeAlias(id) => {
526+
SyntaxNodePtr::new(id.with_file_id(owner.file_id).to_node(db).syntax())
527+
}
469528
}
470529
}
471530

crates/mun_hir/src/code_model/src.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::code_model::{Function, Struct, StructField};
1+
use crate::code_model::{Function, Struct, StructField, TypeAlias};
22
use crate::ids::AstItemDef;
33
use crate::in_file::InFile;
44
use crate::DefDatabase;
@@ -45,3 +45,10 @@ impl HasSource for StructField {
4545
InFile::new(file_id, ast)
4646
}
4747
}
48+
49+
impl HasSource for TypeAlias {
50+
type Ast = ast::TypeAliasDef;
51+
fn source(self, db: &dyn DefDatabase) -> InFile<ast::TypeAliasDef> {
52+
self.id.source(db)
53+
}
54+
}

crates/mun_hir/src/db.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ use crate::name_resolution::Namespace;
55
use crate::ty::lower::LowerBatchResult;
66
use crate::ty::{CallableDef, FnSig, Ty, TypableDef};
77
use crate::{
8-
adt::StructData,
8+
adt::{StructData, TypeAliasData},
99
code_model::{DefWithBody, FnData, Function, ModuleData},
1010
ids,
1111
line_index::LineIndex,
1212
name_resolution::ModuleScope,
1313
ty::InferenceResult,
14-
AstIdMap, ExprScopes, FileId, RawItems, Struct,
14+
AstIdMap, ExprScopes, FileId, RawItems, Struct, TypeAlias,
1515
};
1616
use mun_syntax::{ast, Parse, SourceFile};
1717
use mun_target::abi;
@@ -66,6 +66,9 @@ pub trait DefDatabase: SourceDatabase + Upcast<dyn SourceDatabase> {
6666
#[salsa::invoke(StructData::struct_data_query)]
6767
fn struct_data(&self, id: ids::StructId) -> Arc<StructData>;
6868

69+
#[salsa::invoke(TypeAliasData::type_alias_data_query)]
70+
fn type_alias_data(&self, id: ids::TypeAliasId) -> Arc<TypeAliasData>;
71+
6972
#[salsa::invoke(crate::FnData::fn_data_query)]
7073
fn fn_data(&self, func: Function) -> Arc<FnData>;
7174

@@ -80,6 +83,10 @@ pub trait DefDatabase: SourceDatabase + Upcast<dyn SourceDatabase> {
8083
/// Interns a struct definition
8184
#[salsa::interned]
8285
fn intern_struct(&self, loc: ids::ItemLoc<ast::StructDef>) -> ids::StructId;
86+
87+
/// Interns a type alias definition
88+
#[salsa::interned]
89+
fn intern_type_alias(&self, loc: ids::ItemLoc<ast::TypeAliasDef>) -> ids::TypeAliasId;
8390
}
8491

8592
#[salsa::query_group(HirDatabaseStorage)]
@@ -104,11 +111,15 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
104111
#[salsa::invoke(crate::ty::lower::lower_struct_query)]
105112
fn lower_struct(&self, def: Struct) -> Arc<LowerBatchResult>;
106113

114+
#[salsa::invoke(crate::ty::lower::lower_type_alias_query)]
115+
fn lower_type_alias(&self, def: TypeAlias) -> Arc<LowerBatchResult>;
116+
107117
#[salsa::invoke(crate::ty::callable_item_sig)]
108118
fn callable_sig(&self, def: CallableDef) -> FnSig;
109119

110120
#[salsa::invoke(crate::ty::type_for_def)]
111-
fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;
121+
#[salsa::cycle(crate::ty::type_for_cycle_recover)]
122+
fn type_for_def(&self, def: TypableDef, ns: Namespace) -> (Ty, bool);
112123

113124
#[salsa::invoke(crate::expr::body_hir_query)]
114125
fn body(&self, def: DefWithBody) -> Arc<crate::expr::Body>;

crates/mun_hir/src/diagnostics.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,26 @@ impl Diagnostic for UnresolvedType {
117117
}
118118
}
119119

120+
#[derive(Debug)]
121+
pub struct CyclicType {
122+
pub file: FileId,
123+
pub type_ref: AstPtr<ast::TypeRef>,
124+
}
125+
126+
impl Diagnostic for CyclicType {
127+
fn message(&self) -> String {
128+
"cyclic type".to_string()
129+
}
130+
131+
fn source(&self) -> InFile<SyntaxNodePtr> {
132+
InFile::new(self.file, self.type_ref.syntax_node_ptr())
133+
}
134+
135+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
136+
self
137+
}
138+
}
139+
120140
#[derive(Debug)]
121141
pub struct ExpectedFunction {
122142
pub file: FileId,
@@ -687,3 +707,22 @@ impl Diagnostic for InvalidLiteral {
687707
self
688708
}
689709
}
710+
711+
#[derive(Debug)]
712+
pub struct FreeTypeAliasWithoutTypeRef {
713+
pub type_alias_def: InFile<SyntaxNodePtr>,
714+
}
715+
716+
impl Diagnostic for FreeTypeAliasWithoutTypeRef {
717+
fn message(&self) -> String {
718+
"free type alias without type ref".to_string()
719+
}
720+
721+
fn source(&self) -> InFile<SyntaxNodePtr> {
722+
self.type_alias_def
723+
}
724+
725+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
726+
self
727+
}
728+
}

0 commit comments

Comments
 (0)