Skip to content

Commit

Permalink
feat: type alias
Browse files Browse the repository at this point in the history
  • Loading branch information
sinato committed Aug 25, 2020
1 parent 97f4ca8 commit aebe7b3
Show file tree
Hide file tree
Showing 32 changed files with 476 additions and 25 deletions.
3 changes: 2 additions & 1 deletion crates/mun_codegen/src/ir/file_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub(crate) fn gen_file_group_ir<'db, 'ink>(
ModuleDef::Function(_) => (), // TODO: Extern types?
ModuleDef::Struct(_) => (),
ModuleDef::BuiltinType(_) => (),
ModuleDef::TypeAlias(_) => (),
}
}

Expand Down Expand Up @@ -118,7 +119,7 @@ pub(crate) fn gen_file_group_ir<'db, 'ink>(
ModuleDef::Function(f) => {
type_table_builder.collect_fn(*f);
}
ModuleDef::BuiltinType(_) => (),
ModuleDef::BuiltinType(_) | ModuleDef::TypeAlias(_) => (),
}
}

Expand Down
10 changes: 10 additions & 0 deletions crates/mun_compiler/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,14 @@ mod tests {
"\n\nstruct Foo {\ni: bool\n}\n\nfn main() {\nlet a = Foo { i: false };\nlet b = a.t;\n}"
));
}

#[test]
fn test_free_type_alias_error() {
insta::assert_display_snapshot!(compilation_errors("\n\ntype Foo;"));
}

#[test]
fn test_type_alias_target_undeclared_error() {
insta::assert_display_snapshot!(compilation_errors("\n\ntype Foo = UnknownType;"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
source: crates/mun_compiler/src/diagnostics.rs
expression: "compilation_errors(\"\\n\\ntype Foo;\")"
---
error: free type alias without type ref
--> main.mun:3:1
|
3 | type Foo;
| ^^^^^^^^^ free type alias without type ref
|
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
source: crates/mun_compiler/src/diagnostics.rs
expression: "compilation_errors(\"\\n\\ntype Foo = UnknownType;\")"
---
error: cannot find type `UnknownType` in this scope
--> main.mun:3:12
|
3 | type Foo = UnknownType;
| ^^^^^^^^^^^ not found in this scope
|
41 changes: 40 additions & 1 deletion crates/mun_hir/src/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{fmt, sync::Arc};
use crate::type_ref::{TypeRefBuilder, TypeRefId, TypeRefMap, TypeRefSourceMap};
use crate::{
arena::{Arena, RawId},
ids::{AstItemDef, StructId},
ids::{AstItemDef, StructId, TypeAliasId},
AsName, DefDatabase, Name,
};
use mun_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
Expand Down Expand Up @@ -121,3 +121,42 @@ impl StructData {
&self.type_ref_map
}
}

#[derive(Debug, PartialEq, Eq)]
pub struct TypeAliasData {
pub name: Name,
pub type_ref_id: TypeRefId,
type_ref_map: TypeRefMap,
type_ref_source_map: TypeRefSourceMap,
}
impl TypeAliasData {
pub(crate) fn type_alias_data_query(
db: &dyn DefDatabase,
id: TypeAliasId,
) -> Arc<TypeAliasData> {
let src = id.source(db);
let name = src
.value
.name()
.map(|n| n.as_name())
.unwrap_or_else(Name::missing);
let mut type_ref_builder = TypeRefBuilder::default();
let type_ref_opt = src.value.type_ref();
let type_ref_id = type_ref_builder.alloc_from_node_opt(type_ref_opt.as_ref());
let (type_ref_map, type_ref_source_map) = type_ref_builder.finish();
Arc::new(TypeAliasData {
name,
type_ref_id,
type_ref_map,
type_ref_source_map,
})
}

pub fn type_ref_source_map(&self) -> &TypeRefSourceMap {
&self.type_ref_source_map
}

pub fn type_ref_map(&self) -> &TypeRefMap {
&self.type_ref_map
}
}
67 changes: 62 additions & 5 deletions crates/mun_hir/src/code_model.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
pub(crate) mod src;

use self::src::HasSource;
use crate::adt::{StructData, StructFieldId};
use crate::adt::{StructData, StructFieldId, TypeAliasData};
use crate::builtin_type::BuiltinType;
use crate::code_model::diagnostics::ModuleDefinitionDiagnostic;
use crate::diagnostics::DiagnosticSink;
use crate::expr::validator::ExprValidator;
use crate::expr::validator::{ExprValidator, TypeAliasValidator};
use crate::expr::{Body, BodySourceMap};
use crate::ids::AstItemDef;
use crate::ids::LocationCtx;
Expand All @@ -15,7 +15,7 @@ use crate::resolve::{Resolution, Resolver};
use crate::ty::{lower::LowerBatchResult, InferenceResult};
use crate::type_ref::{TypeRefBuilder, TypeRefId, TypeRefMap, TypeRefSourceMap};
use crate::{
ids::{FunctionId, StructId},
ids::{FunctionId, StructId, TypeAliasId},
AsName, DefDatabase, FileId, HirDatabase, Name, Ty,
};
use mun_syntax::ast::{ExternOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner};
Expand Down Expand Up @@ -52,11 +52,11 @@ impl Module {
diag.add_to(db.upcast(), self, sink);
}
for decl in self.declarations(db) {
#[allow(clippy::single_match)]
match decl {
ModuleDef::Function(f) => f.diagnostics(db, sink),
ModuleDef::Struct(s) => s.diagnostics(db, sink),
_ => (),
ModuleDef::TypeAlias(t) => t.diagnostics(db, sink),
ModuleDef::BuiltinType(_) => (),
}
}
}
Expand Down Expand Up @@ -104,6 +104,11 @@ impl ModuleData {
id: StructId::from_ast_id(loc_ctx, ast_id),
}))
}
DefKind::TypeAlias(ast_id) => {
data.definitions.push(ModuleDef::TypeAlias(TypeAlias {
id: TypeAliasId::from_ast_id(loc_ctx, ast_id),
}))
}
}
}
};
Expand All @@ -121,6 +126,7 @@ pub enum ModuleDef {
Function(Function),
BuiltinType(BuiltinType),
Struct(Struct),
TypeAlias(TypeAlias),
}

impl From<Function> for ModuleDef {
Expand Down Expand Up @@ -442,6 +448,54 @@ impl Struct {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeAlias {
pub(crate) id: TypeAliasId,
}

impl TypeAlias {
pub fn module(self, db: &dyn DefDatabase) -> Module {
Module {
file_id: self.id.file_id(db),
}
}

pub fn data(self, db: &dyn DefDatabase) -> Arc<TypeAliasData> {
db.type_alias_data(self.id)
}

pub fn name(self, db: &dyn DefDatabase) -> Name {
self.data(db).name.clone()
}

pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRefId {
self.data(db.upcast()).type_ref_id
}

pub fn lower(self, db: &dyn HirDatabase) -> Arc<LowerBatchResult> {
db.lower_type_alias(self)
}

pub(crate) fn resolver(self, db: &dyn HirDatabase) -> Resolver {
// take the outer scope...
self.module(db.upcast()).resolver(db.upcast())
}

pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
let data = self.data(db.upcast());
let lower = self.lower(db);
lower.add_diagnostics(
db,
self.module(db.upcast()).file_id,
data.type_ref_source_map(),
sink,
);

let validator = TypeAliasValidator::new(self, db);
validator.validate_target_type_existence(sink);
}
}

mod diagnostics {
use super::Module;
use crate::diagnostics::{DiagnosticSink, DuplicateDefinition};
Expand All @@ -466,6 +520,9 @@ mod diagnostics {
DefKind::Struct(id) => {
SyntaxNodePtr::new(id.with_file_id(owner.file_id).to_node(db).syntax())
}
DefKind::TypeAlias(id) => {
SyntaxNodePtr::new(id.with_file_id(owner.file_id).to_node(db).syntax())
}
}
}

Expand Down
9 changes: 8 additions & 1 deletion crates/mun_hir/src/code_model/src.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::code_model::{Function, Struct, StructField};
use crate::code_model::{Function, Struct, StructField, TypeAlias};
use crate::ids::AstItemDef;
use crate::in_file::InFile;
use crate::DefDatabase;
Expand Down Expand Up @@ -45,3 +45,10 @@ impl HasSource for StructField {
InFile::new(file_id, ast)
}
}

impl HasSource for TypeAlias {
type Ast = ast::TypeAliasDef;
fn source(self, db: &dyn DefDatabase) -> InFile<ast::TypeAliasDef> {
self.id.source(db)
}
}
15 changes: 13 additions & 2 deletions crates/mun_hir/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use crate::name_resolution::Namespace;
use crate::ty::lower::LowerBatchResult;
use crate::ty::{CallableDef, FnSig, Ty, TypableDef};
use crate::{
adt::StructData,
adt::{StructData, TypeAliasData},
code_model::{DefWithBody, FnData, Function, ModuleData},
ids,
line_index::LineIndex,
name_resolution::ModuleScope,
ty::InferenceResult,
AstIdMap, ExprScopes, FileId, RawItems, Struct,
AstIdMap, ExprScopes, FileId, RawItems, Struct, TypeAlias,
};
use mun_syntax::{ast, Parse, SourceFile};
use mun_target::abi;
Expand Down Expand Up @@ -66,6 +66,9 @@ pub trait DefDatabase: SourceDatabase + Upcast<dyn SourceDatabase> {
#[salsa::invoke(StructData::struct_data_query)]
fn struct_data(&self, id: ids::StructId) -> Arc<StructData>;

#[salsa::invoke(TypeAliasData::type_alias_data_query)]
fn type_alias_data(&self, id: ids::TypeAliasId) -> Arc<TypeAliasData>;

#[salsa::invoke(crate::FnData::fn_data_query)]
fn fn_data(&self, func: Function) -> Arc<FnData>;

Expand All @@ -80,6 +83,10 @@ pub trait DefDatabase: SourceDatabase + Upcast<dyn SourceDatabase> {
/// Interns a struct definition
#[salsa::interned]
fn intern_struct(&self, loc: ids::ItemLoc<ast::StructDef>) -> ids::StructId;

/// Interns a type alias definition
#[salsa::interned]
fn intern_type_alias(&self, loc: ids::ItemLoc<ast::TypeAliasDef>) -> ids::TypeAliasId;
}

#[salsa::query_group(HirDatabaseStorage)]
Expand All @@ -104,10 +111,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::ty::lower::lower_struct_query)]
fn lower_struct(&self, def: Struct) -> Arc<LowerBatchResult>;

#[salsa::invoke(crate::ty::lower::lower_type_alias_query)]
fn lower_type_alias(&self, def: TypeAlias) -> Arc<LowerBatchResult>;

#[salsa::invoke(crate::ty::callable_item_sig)]
fn callable_sig(&self, def: CallableDef) -> FnSig;

#[salsa::invoke(crate::ty::type_for_def)]
#[salsa::cycle(crate::ty::type_for_cycle_recover)]
fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;

#[salsa::invoke(crate::expr::body_hir_query)]
Expand Down
19 changes: 19 additions & 0 deletions crates/mun_hir/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,3 +687,22 @@ impl Diagnostic for InvalidLiteral {
self
}
}

#[derive(Debug)]
pub struct FreeTypeAliasWithoutTypeRef {
pub type_alias_def: InFile<SyntaxNodePtr>,
}

impl Diagnostic for FreeTypeAliasWithoutTypeRef {
fn message(&self) -> String {
"free type alias without type ref".to_string()
}

fn source(&self) -> InFile<SyntaxNodePtr> {
self.type_alias_def
}

fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
}
30 changes: 28 additions & 2 deletions crates/mun_hir/src/expr/validator.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use crate::code_model::src::HasSource;
use crate::diagnostics::{ExternCannotHaveBody, ExternNonPrimitiveParam};
use crate::diagnostics::{
ExternCannotHaveBody, ExternNonPrimitiveParam, FreeTypeAliasWithoutTypeRef,
};
use crate::expr::BodySourceMap;
use crate::in_file::InFile;
use crate::{diagnostics::DiagnosticSink, Body, Expr, Function, HirDatabase, InferenceResult};
use crate::{
diagnostics::DiagnosticSink, Body, Expr, Function, HirDatabase, InferenceResult, TypeAlias,
};
use mun_syntax::{AstNode, SyntaxNodePtr};
use std::sync::Arc;

Expand Down Expand Up @@ -83,3 +87,25 @@ impl<'a> ExprValidator<'a> {
}
}
}

pub struct TypeAliasValidator<'a> {
type_alias: TypeAlias,
db: &'a dyn HirDatabase,
}

impl<'a> TypeAliasValidator<'a> {
/// Constructs a validator for the provided `TypeAlias`.
pub fn new(type_alias: TypeAlias, db: &'a dyn HirDatabase) -> Self {
TypeAliasValidator { type_alias, db }
}

/// Validates that the provided `TypeAlias` has a target type of alias.
pub fn validate_target_type_existence(&self, sink: &mut DiagnosticSink) {
let src = self.type_alias.source(self.db.upcast());
if src.value.type_ref().is_none() {
sink.push(FreeTypeAliasWithoutTypeRef {
type_alias_def: src.map(|t| SyntaxNodePtr::new(t.syntax())),
})
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: crates/mun_hir/src/expr/validator/tests.rs
expression: "type Foo; // `Foo` must have a target type"
---
[0; 9): free type alias without type ref

Loading

0 comments on commit aebe7b3

Please sign in to comment.